piskelapp/piskel
35.8
Weak · 1 October 2026
40k
lines of production code
JavaScript
primary language
2
measurements over time
What this system is
Piskel is a browser-based pixel art editor and animation tool that provides a comprehensive suite of drawing, layering, and frame management capabilities. It supports complex workflows through features like onion skinning, lasso and shape selection, and an import/merge wizard for combining images and spritesheets. The system handles persistent storage via IndexedDB, offers extensive export options for PNG, GIF, and ZIP formats, and includes a CLI for batch processing. It is packaged for desktop environments and utilizes a modern Vite build pipeline with Playwright for end-to-end testing.
How it got here
2012–2014 — Architecture modernization and tool expansion
39 changes.
The project underwent a significant architectural overhaul, introducing a modular controller-based structure, centralized constants, and a robust rendering engine with onion skinning and caching. This period also saw the expansion of core functionality with new drawing tools, selection methods, and transform operations, alongside the addition of GIF generation and palette import features.
2015–2017 — Web Worker offloading and IndexedDB migration
21 changes.
This period focused on improving application performance and reliability by offloading CPU-intensive tasks like hash computation and color analysis to Web Workers. It also involved a significant infrastructure shift, migrating local storage persistence from LocalStorage to IndexedDB and unifying the save service. Additionally, the editor gained new capabilities through an import/merge wizard, expanded export options, and refined user preferences.
2018–2026 — Build system modernization and test expansion
6 changes.
The project migrated its build pipeline from Grunt to Vite, introducing custom Node.js scripts for desktop packaging and asset generation while enforcing code quality via Husky. This period also focused on expanding test coverage by adding comprehensive unit tests for core components and e2e fixtures for drawing tools, alongside the introduction of a new CLI for exporting animations.
Features
Add GIF.js library for animated GIF generation
Added the gif.js library (version 0.1.6) to the project, including the main \gif.js\ module, the \gif.worker.js\ background worker for encoding, and \libgif.js\ for GIF parsing. This enables the application to generate animated GIFs from canvas frames using a Web Worker for performance.
src/js/lib/gif · high confidence
Add Piskel CLI for exporting .piskel files to PNG
Introduces a new command-line interface (piskel-cli) that allows users to export .piskel animation files to PNG sprite sheets directly from the terminal. The tool supports various export options including scaling (via --scale, --scaledWidth, or --scaledHeight), cropping (--crop), specific frame extraction (--frame), and layout control (--rows, --columns). It also offers the ability to generate a data URI file (--dataUri) and specify a custom output path (--dest).
cli · high confidence
Added Blob polyfill for legacy browser support
A new Blob polyfill has been added to the devtools library to support older browsers that only provide BlobBuilder. This implementation ensures that Blob and URL APIs function correctly in environments like PhantomJS by providing fallback logic for creating object URLs and handling binary data.
src/js/devtools/lib · high confidence
Added UI prototype and Bootstrap tooltip library
Added a new UI prototype in misc/proto-ui-1 that provides a tile-based drawing interface with tools (pen, bucket, magic wand, eyedropper), a canvas with selectable background textures, and a preview list with drag-and-drop state toggles. Included jQuery 1.8.0 and a custom Bootstrap build containing only the tooltip component (v2.1.1) in src/js/lib/bootstrap to support interactive UI elements.
misc/proto-ui-1, src/js/lib/bootstrap · high confidence
Added dedicated drag handler for canvas panning
A new DragHandler component has been introduced to manage viewport panning via mouse drag interactions. This controller calculates offset adjustments based on mouse movement, applying a multiplier to determine the final pan distance, and integrates with the drawing controller to update the canvas position during drag sessions.
src/js/controller/drawing · high confidence
Added desktop packaging scripts and configuration
New scripts and configuration files have been added to support building and packaging the Piskel desktop application for macOS and Windows. This includes an Info.plist for macOS app metadata, shell and batch scripts to assemble the application bundles (including icon injection and resource copying), and a Node.js utility to locate the release build root.
misc/scripts · high confidence
Automatic migration of saved sprites from LocalStorage to IndexedDB
Users will now have their existing saved sprites automatically migrated from the browser's LocalStorage to the more robust IndexedDB storage. This new migration utility scans for all previously saved piskels, transfers their data (name, description, date, and serialized content) into the new database system, and subsequently removes the old LocalStorage entries to free up space. This ensures that user data persists reliably without manual intervention.
src/js/database/migrate · high confidence
Introduce core animation model classes
The application now uses dedicated model classes to manage animation data: Frame handles individual pixel grids and their versions, Layer manages collections of frames with opacity support, Palette stores color definitions, and Piskel orchestrates the overall animation by managing layers, dimensions, and frame rate. This structural change provides a more robust foundation for features like layer opacity, frame management, and animation playback.
src/js/model · high confidence
Introduction of core tool infrastructure and frame-targeting helpers
This change introduces the foundational structure for drawing tools in the application. It adds a base Tool class that standardizes tool identification and help text, along with a ToolIconBuilder that generates UI icons and tooltips for each tool. Additionally, a new ToolsHelper module provides logic to determine which frames and layers are affected by tool actions, supporting modes to target the current frame/layer or all frames/layers, which enables more flexible tool behavior across the canvas.
src/js/tools · high confidence
Introduction of modular utility library in src/js/utils
This change introduces a new, organized set of utility modules under src/js/utils to replace scattered inline code. The diff adds dedicated files for core operations: Array (chunking), Base64 (decoding), BlobUtils (data-to-blob conversion), CanvasUtils (canvas creation, image smoothing, cloning), ColorUtils (finding unused colors), DateUtils (formatting), Dom (parent checks, data attributes), Environment (Node-Webkit/HTTPS detection), Event (managed add/remove listeners to prevent leaks), FileUtils (file reading, downloads), FileUtilsDesktop (Node-Webkit specific file I/O), FrameUtils (frame rendering, merging, resizing, image insertion), FunctionUtils (memoization, throttling), ImageResizer (scaling with smoothing control), LayerUtils (layer cloning, merging, frame flattening), Math (min/max, distance), MergeUtils (merging Piskel instances), PiskelFileUtils (loading/decoding .piskel files), PixelUtils (connected pixel visits, paintbucket logic, pixel resizing), ResizeUtils (Piskel/layer/frame resizing with origin handling), StringUtils (padding, size formatting), Template (HTML template rendering with sanitization), TooltipFormatter (tooltip generation), UserAgent (browser detection/versioning), and UserSettings (persistent user preferences). This refactoring centralizes common logic, improves maintainability, and adds specific capabilities like memory-safe event handling and robust template sanitization.
src/js/utils · high confidence
New ArrayBuffer serialization format for in-memory animation backup
The application now supports serializing and deserializing animations into a compact ArrayBuffer format, specifically designed for backing up animation state in memory rather than exporting to strings. This new serializer and deserializer handle the full animation structure, including Piskel metadata (width, height, FPS), descriptor details, layer information (name, opacity, frame count), and hidden frames. By using binary buffers, this approach avoids browser compatibility issues with TypedArray string conversion and provides a more efficient internal representation for saving and restoring animation state.
src/js/utils/serialization/arraybuffer · high confidence
New Import and Merge Wizard for images and Piskel files
Users can now import images or Piskel files through a multi-step wizard dialog that supports both replacing the current project and merging new content. The wizard adapts its steps based on the input: single image imports trigger an image import step, while Piskel files skip directly to mode selection. When merging, the wizard allows users to adjust size, choose insertion location, and select the merge mode. After a merge operation, the first imported layer is automatically selected to facilitate immediate editing.
src/js/controller/dialogs/importwizard · high confidence
New Import and Merge Wizard with multi-step configuration
The application now features a new Import and Merge wizard dialog that guides users through importing images and spritesheets into their Piskel projects. This wizard introduces a multi-step flow allowing users to first choose between replacing or merging content, then configure import specifics such as resizing options (keeping original size or expanding), setting resize anchors, and defining frame grid parameters for spritesheets. Finally, users can select the insertion location within the current animation. The wizard also handles edge cases like skipping steps if the current Piskel is empty and persisting the preview UI during the import process.
src/js/controller/dialogs/importwizard/steps · high confidence
New UI widgets for frame navigation, color management, and guided workflows
This update introduces several new interactive components to the application's interface. The FramePicker widget allows users to browse and select specific frames within an animation, while the AnchorWidget provides a visual grid for setting resize origins. Color management is enhanced with the ColorsList widget for palette editing and the HslRgbColorPicker for precise color selection. Additionally, the SizePicker and SizeInput widgets simplify dimension adjustments with synchronized width/height inputs, and the Tabs widget enables organized settings panels. A new Wizard widget provides a step-by-step interface for guided workflows, such as import and merge operations.
src/js/widgets · high confidence
New browse-backups dialog for managing saved sessions
Users can now open a new dialog to browse, view, and delete saved backup sessions. The dialog presents a list of past sessions (excluding the current one) with details like name, date, and snapshot count. Selecting a session reveals its individual snapshots, including visual previews of the first frame, allowing users to load a specific snapshot back into the editor. Users can also delete unwanted sessions directly from the list, with a confirmation prompt and visual feedback during the removal process.
src/js/controller/dialogs/backups · high confidence
New controller architecture for UI components
The application introduces a set of dedicated controllers to manage specific UI areas, replacing previous inline or monolithic logic. These include CanvasBackgroundController for background settings, CursorCoordinatesController for displaying cursor position and zoom, DrawingController for the main canvas and tool interactions, FramesListController for the animation timeline, HeaderController for the app title, LayersListController for layer management, MinimapController for the overview map, NotificationController for user messages, PaletteController for color selection, PalettesListController for palette management, PenSizeController for brush size, ProgressBarController for operation status, ToolController for the drawing tools, TransformationsController for image transforms, and UserWarningController for performance alerts. This change organizes the codebase into distinct, manageable components for each UI feature.
src/js/controller · high confidence
New dialog infrastructure and palette management
The application now features a centralized DialogsController that manages the lifecycle of various modal windows, including a new Cheatsheet dialog for viewing and editing keyboard shortcuts, a Create Palette dialog for managing color palettes (creating, editing, importing, and deleting), and a Browse Local dialog for managing locally stored projects. Additionally, warning dialogs for unsupported browsers and performance issues have been added, all sharing a common AbstractDialogController base class for consistent initialization and cleanup.
src/js/controller/dialogs · high confidence
New dialogs for backups, local storage, palettes, and import workflows
Added template files for several new user-facing dialogs: a 'Browse backups' dialog to restore automatically saved sessions, a 'Browse Local Piskels' dialog for managing local storage, a 'Create palette' dialog with color picker and import/export options, an 'Import and Merge' wizard for handling image imports and spritesheet creation, a 'Keyboard shortcuts' cheatsheet dialog, and informational dialogs for performance warnings and unsupported browsers.
src/templates/dialogs · high confidence
New drawing test tooling for recording and replaying user interactions
A new set of development tools has been added to the devtools module to support automated testing of drawing actions. The \DrawingTestRecorder\ captures user interactions—including mouse events, keyboard shortcuts, tool selections, color changes, pen size adjustments, and clipboard operations—and serializes them into a JSON test record along with the initial canvas state and a reference PNG. The \DrawingTestPlayer\ replays these recorded events in the application, handling platform-specific nuances (such as mapping Ctrl to Meta on macOS) and adding delays for asynchronous operations like undo/redo or transform tools to ensure stable state before comparison. The \TestRecordController\ provides a UI for starting/stopping recordings and loading existing test files, while the \DrawingTestRunner\ and \DrawingTestSuiteController\ enable executing single tests or full suites from URLs, displaying pass/fail status and performance metrics in the browser.
src/js/devtools · high confidence
New lasso and shape selection tools added
Users can now create freeform selections using the new Lasso tool and select contiguous areas of similar color using the new Shape tool. These are added alongside the existing Rectangle and Marquee selection tools, all of which have been refactored into a shared base class structure to support consistent behavior like moving selections and clipboard operations.
src/js/tools/drawing/selection · high confidence
New lasso selection tool and refactored selection architecture
Users can now create freeform selections using the new lasso tool, which identifies pixels inside a drawn shape. The selection system has been refactored to support multiple selection types (rectangular, lasso, and shape) via a shared BaseSelection interface, improving how selections are managed, copied, and pasted within the application.
src/js/selection · high confidence
New preferences settings for grid, tile mode, and misc options
Users can now configure grid visibility, size, spacing, and color through the new grid preferences panel, enable tile mode with adjustable mask opacity, and adjust background contrast, layer opacity, maximum FPS, and color format (Hex/RGB) via the misc preferences panel.
src/templates/settings/preferences · high confidence
New rendering architecture with onion skin support
The rendering subsystem has been restructured to use a new set of renderer classes (AbstractRenderer, CanvasRenderer, CompositeRenderer, etc.) that handle frame drawing, scaling, and compositing. A key user-facing change is the addition of an onion skin feature, implemented via OnionSkinRenderer, which displays previous and next frames to aid animation. The system also introduces a DrawingLoop for managing animation frames and specific renderers for generating framesheets and tiled previews.
src/js/rendering · high confidence
New transform tools: Crop, Clone, Center, Flip, and Rotate
The transform tools section now includes a new Crop tool that resizes the sprite to fit the current selection or content boundaries, a Clone tool that copies the current frame's pixels to all other frames in the current layer, and a Center tool that aligns the image content to the center of the frame. Existing Flip and Rotate tools have been refactored into this new structure, supporting modifiers to apply changes to all layers (Ctrl/Cmd) or all frames (Shift), with Alt/Cmd toggling flip axis or rotation direction. These tools share a common AbstractTransformTool base for consistent state replay and shortcut handling.
src/js/tools/transform · high confidence
Support for importing .PAL, .GPL, .TXT, and image-based palettes
Users can now import color palettes from multiple sources, including Adobe .GPL and .PAL text files, simple .TXT hex files, and images. The system introduces dedicated readers for each format: .GPL and .PAL files are parsed by extracting RGB values from their respective line formats, .TXT files are read as lowercase hex strings, and image files are processed via a Web Worker to extract and sort dominant colors. All imported colors are normalized to lowercase hex strings for consistency.
src/js/service/palette/reader · high confidence
Architecture
Extracted UI components into modular HTML templates
The application's user interface has been restructured by extracting distinct UI sections into separate, reusable HTML template files within the \src/templates\ directory. This change introduces dedicated templates for the drawing tools and color pickers (\drawing-tools.html\), layer management (\layers-list.html\), palette management (\palettes-list.html\), and animation preview controls (\preview.html\). Additional templates handle specific features such as the popup preview (\popup-preview.html\), data-uri export viewer (\data-uri-export.html\), and a debug header (\debug-header.html\). This modularization separates the structural markup for these components from the main application bundle, improving maintainability and allowing for more granular loading or inclusion of interface parts.
src/templates · high confidence
Introduce centralized constants and event definitions
The application now uses a new Constants.js file to define core configuration values, including default sprite dimensions (32x32), frame rate (12 FPS), and the maximum palette size (256 colors). A new Events.js file centralizes all application event names, such as tool selection, color changes, and save states, replacing scattered string literals. The main app.js entry point has been refactored to initialize a comprehensive set of services and controllers, including storage, palette, and drawing management, establishing a more structured initialization flow.
src/js · high confidence
Behavioural changes
Add Spectrum Colorpicker CSS and Piskel-specific overrides
This change introduces the base styles for the Spectrum Colorpicker (v1.1.2) via \src/css/spectrum/spectrum.css\ and applies Piskel-specific visual customizations in \src/css/spectrum/spectrum-overrides.css\. The overrides adjust the color picker's appearance to match the application's dark theme, including a dark background, specific border radii, and hidden dropdown triangles. It also enforces a monospace font for the color input field and adjusts padding and sizing for the palette and slider components to fit the UI layout.
src/css/spectrum · high confidence
Enforce linting on pre-commit via Husky
A new pre-commit hook has been added to the project using Husky. This hook automatically runs \npm run lint\ before every commit, ensuring that code quality checks are enforced at the source control level. This change replaces the deprecated npm \precommit\ script with the standard Husky workflow.
.husky · high confidence
Introduction of CSS variables and modular stylesheet architecture
The application's styling has been refactored to use CSS custom properties (variables), specifically introducing a \--highlight-color\ variable that replaces hardcoded gold/primary color values across the interface. This change is accompanied by a structural reorganization where the monolithic styles have been split into a modular set of dedicated files (e.g., \animations.css\, \color-picker-slider.css\, \dialogs-\.css\, \settings-\.css\, \toolbox-\*.css\), improving maintainability and allowing specific UI components like dialogs, settings panels, and the toolbox to be styled independently.
src/css · high confidence
Introduction of PiskelController with public event-driven API
The application now uses a dedicated PiskelController to manage the core piskel model state, including frame and layer manipulation, alongside a PublicPiskelController decorator that exposes this functionality to the rest of the application. This decorator automatically fires PISKEL\_RESET and PISKEL\_SAVE\_STATE events for specific actions (such as adding/removing frames, duplicating layers, or changing opacity), enabling other components to react to changes and supporting history/replay capabilities without requiring direct coupling to the model.
src/js/controller/piskel · high confidence
Keyboard shortcuts for adjusting pen size
Users can now increase or decrease the pen size using keyboard shortcuts. The PenSizeService registers handlers for the INCREASE\_PENSIZE and DECREASE\_PENSIZE shortcuts, which adjust the current size by +1 or -1 respectively. The pen size is constrained to a valid range of 1 to 32 pixels, and changes are persisted to user settings and broadcast via an event.
src/js/service/pensize · high confidence
Layer preview opacity support and rendering stability
The LayersRenderer now respects the user's layer opacity preference, applying it via a dynamic stylesheet to the layer canvases. This change also introduces a safeguard in setDisplaySize to prevent canvas destruction during invalid size calls and implements a serialized rendering check to optimize performance by avoiding unnecessary re-renders when layer state has not changed.
src/js/rendering/layer · high confidence
Migrate build pipeline from Grunt to Vite plugins
The build system in the vite-plugins directory has been replaced with a new set of Vite plugins, removing legacy Grunt and IE11-specific code. The new pipeline includes a script concatenation plugin that bundles JavaScript with source maps and minification, a CSS plugin that replaces specific variables (such as --highlight-color) with hardcoded values, and an HTML processing plugin that handles template includes and version variable substitution. This change updates how static assets are processed and emitted during the build.
vite-plugins · high confidence
Migrate build system to Vite and testing to Playwright
The project has replaced the Grunt build tool with Vite, introducing a new configuration (vite.config.js) and custom plugins to handle script concatenation and HTML inclusion, while the build output is now directed to dest/prod. Additionally, the testing infrastructure has shifted from CasperJS/PhantomJS to Playwright for end-to-end tests and Karma with ChromeHeadless for unit tests, supported by new configuration files (playwright.config.ts, karma.conf.js) and a CI script (run-test-ci.sh).
(repo-wide) · high confidence
Migrate local storage persistence to IndexedDB
The application's local persistence layer has been replaced with IndexedDB, introducing dedicated database modules for managing saved projects (PiskelDatabase) and automatic session backups (BackupDatabase). This change includes a migration script that automatically transfers existing data from the legacy localStorage to the new IndexedDB stores, ensuring a seamless transition for users without data loss.
src/js/database · high confidence
New chunked serialization and backward-compatible deserialization for sprite layers
The serialization utility now handles large sprite layers by splitting them into multiple chunks (base64 PNG spritesheets) to avoid data URL size limits, ensuring projects save reliably even with many frames. On load, the new deserializer supports the current model version as well as legacy versions (0 and 1), automatically normalizing older single-image layer formats into the new chunked structure. This change also preserves layer opacity and hidden frame data during save/load cycles.
src/js/utils/serialization · high confidence
New default size preference and refined resize controls
Users can now set a default canvas size that persists across sessions via the new Default Size settings panel. The main Resize dialog has been updated to use a dedicated SizeInput widget for width and height entry, and resize preferences (such as maintaining aspect ratio, resizing content, and anchor origin) are now explicitly saved to user settings for persistence.
src/js/controller/settings/resize · high confidence
New preferences controllers for grid, misc, and tile settings
The application now includes dedicated controllers for managing specific user preferences: GridPreferencesController handles grid visibility, size, spacing, and color; MiscPreferencesController manages canvas background, maximum FPS, color format, and layer preview opacity; and TilePreferencesController controls seamless mode and tile mask opacity. These changes restructure how these settings are initialized and updated within the preferences UI.
src/js/controller/settings/preferences · high confidence
Offload frame color detection to a Web Worker
The frame color detection logic has been moved from the main thread to a dedicated Web Worker (FrameColorsWorker). This change allows the application to detect up to 256 distinct colors per frame without blocking the user interface, as the heavy pixel iteration is now performed asynchronously in the background.
src/js/worker/framecolors · high confidence
Offload hash computation to a Web Worker
Hash calculation is now performed in a background Web Worker instead of the main thread. This change prevents UI blocking during hash generation by delegating the CPU-intensive string hashing logic to a separate worker process, allowing the application to remain responsive while the hash is being computed.
src/js/worker/hash · high confidence
Offload image color analysis to a background worker
The image processor now uses a Web Worker to compute the color map of an image, preventing the main thread from blocking during this operation. The new ImageProcessor component sends image data to ImageProcessorWorker, which iterates through pixels to build a map of unique colors while reporting progress steps back to the main thread for UI updates.
src/js/worker/imageprocessor · high confidence
Palette service restructured with new import/export and storage capabilities
The palette management system has been reorganized into the \pskl.service.palette\ namespace, introducing a dedicated \PaletteService\ that now handles palette persistence via \localStorageGlobal\ and manages dynamic palettes. A new \PaletteImportService\ enables users to import palettes from various file formats (GPL, PAL, TXT, and images) by delegating to specific readers, while \PaletteGplWriter\ allows exporting palettes in GIMP-compatible format. Additionally, a \CurrentColorsPalette\ type was added to allow palettes to dynamically reflect the currently selected colors in the editor.
src/js/service/palette · high confidence
Performance warning system for complex sprites
Piskel now automatically analyzes sprite complexity and displays a warning if the animation exceeds recommended limits. The new performance service checks resolution (over 512x512), layer count (over 25), frame count (over 100), and color count (256 or more) against a calculated score. When these thresholds are breached, users are notified via a save-to-gallery warning to help prevent performance issues during editing.
src/js/service/performance · high confidence
Redesigned drawing tools with unified base classes and enhanced shape/line rendering
The drawing tools in the editor have been refactored to use a new \BaseTool\ and \SimplePen\ architecture, introducing a consistent \getToolColor\ method that respects primary/secondary color selection and right-click modifiers. The Stroke tool now supports dynamic pen sizes and draws lines with square ends, while the Circle and Rectangle shape tools have been rewritten to handle large pen sizes and even dimensions more accurately. The Move tool now correctly applies shifts to all layers and frames when modifier keys are held, and the ColorSwap tool has been updated to handle case-insensitive color matching. Additionally, a new Dithering tool has been added, and the Lighten tool now supports both lightening and darkening (via Ctrl/Meta) with a 'once per pixel' option.
src/js/tools/drawing · high confidence
Refactored core services for improved stability and performance
The service layer has been significantly restructured to enhance reliability and user experience. The HistoryService now uses a linked-list approach with UUIDs and limits undo/redo operations to the last 500 states to prevent performance degradation. The BackupService has been migrated to use IndexedDB for persistent storage, allowing for automatic backups and snapshot management. The CurrentColorsService now utilizes a web worker for color calculation and includes caching to improve responsiveness. Additionally, new services like BeforeUnloadService and SavedStatusService ensure users are warned about unsaved changes when closing the application, while the ColorSorter provides a more intuitive palette organization.
src/js/service · high confidence
Refactored frame caching with async support and LRU eviction
The frame processing model now uses a new \CachedFrameProcessor\ that enforces a maximum cache size of 100 entries using an LRU (Least Recently Used) eviction strategy, preventing unbounded memory growth. A new \AsyncCachedFrameProcessor\ subclass has been introduced to handle cache lookups asynchronously via Promises, allowing non-blocking retrieval of processed frames. Additionally, a \RenderedFrame\ class was added to support pre-rendered images, enabling the reuse of merged transparent frames to avoid redundant processing in compatible renderers.
src/js/model/frame · high confidence
Refactored frame rendering with caching and zoom limits
The frame rendering logic in src/js/rendering/frame has been restructured to improve performance and stability. A new CachedFrameRenderer prevents unnecessary redraws by tracking state changes, while the core FrameRenderer now enforces zoom limits (1x to 10x sprite pixels) to ensure consistent display. Additionally, a BackgroundImageFrameRenderer was introduced to handle background rendering via CSS, and grid settings are now properly integrated into the rendering pipeline.
src/js/rendering/frame · high confidence
Refactored keyboard shortcut system with dynamic remapping and new shortcuts
The keyboard service has been restructured to use a new \Shortcut\ class and \ShortcutService\, replacing the previous implementation. This change introduces the ability to dynamically remap most keyboard shortcuts via user settings, while protecting specific keys (like 1-9 for palette colors and navigation keys) from being changed. The refactoring also adds several new shortcuts, including Ctrl+Shift+Z for redo, Alt+G to toggle the grid, Shift+Arrow keys to move the viewport, and keys 1-9 to quickly select palette colors.
src/js/service/keyboard · high confidence
Refactored preview system with popup support and size controls
The preview functionality has been restructured into dedicated controllers: PreviewController manages the main preview area and throttles rendering to 300ms, PreviewActionsController handles UI interactions like the new preview size dropdown (original, best, full) and grid toggle, and PopupPreviewController enables opening the animation in a separate browser window. This change also introduces keyboard shortcuts for preview size selection and onion skin toggling, and ensures the popup preview stays synchronized with the main canvas.
src/js/controller/preview · high confidence
Refactored settings drawer into modular controllers
The settings interface has been restructured to use a new AbstractSettingController base class, with specific logic moved into dedicated controllers for Import, Preferences, and Save operations. This change improves the maintainability of the settings drawer by isolating concerns, such as handling file imports, managing user preferences tabs, and controlling save actions (including desktop and IndexedDB storage), while ensuring proper event listener cleanup when switching between settings sections.
src/js/controller/settings · high confidence
Replaces Grunt build system with Vite and custom Node.js scripts
The project's build tooling has been migrated from Grunt to Vite, introducing a new set of Node.js scripts to handle development and packaging tasks. A new \scripts/desktop.js\ script manages NW.js desktop app builds for Windows, Linux, and macOS, including binary caching and platform-specific configuration. Development workflow is handled by \scripts/serve.js\, which provides a local server with live reload capabilities (hot-swapping CSS and auto-refreshing JS/HTML changes) and supports a test mode for E2E testing. Additionally, \scripts/partials.js\ generates website-compatible HTML variants for integration with piskelapp.com, and \scripts/sprite.js\ automates the generation of icon sprite sheets and corresponding CSS for both standard and retina displays.
scripts · high confidence
Restructured export settings into a tabbed interface with new export options
The export settings panel has been refactored into a tabbed interface (PNG, GIF, ZIP, Misc) managed by a new ExportController, replacing the previous flat layout. This change introduces several new capabilities: ZIP exports can now be split by layer with optional layer-name prefixes; GIF exports support a repeat toggle and improved transparency handling when color limits are exceeded; PNG exports allow custom spritesheet grid layouts (rows/columns) and offer a PixiJS download option with inline image support; and a new Misc tab enables downloading the sprite data as a C header file for embedded use.
src/js/controller/settings/exportimage · high confidence
Restructured export settings with new format options and UI improvements
The export settings interface has been reorganized into dedicated tabs for GIF, PNG, ZIP, and miscellaneous formats. The PNG tab now allows users to configure spritesheet layout (columns/rows), export as a data-uri, generate a PixiJS movie with an optional inline image, and download a single selected frame. The GIF tab includes a warning for color loss and a loop toggle. The ZIP export supports a filename prefix and options to split by layers or index by layer names. A new miscellaneous tab allows exporting frames as a C file.
src/templates/settings/export · high confidence
Restructured settings interface with dedicated export, import, and save templates
The application settings panel has been reorganized into distinct, modular sections defined by new HTML templates. The Export section now features a unified interface with tabs for GIF, PNG, Zip, and Other formats, including controls for scaling and resolution. The Import section provides options to load local browser saves, open .piskel files, import images (PNG, JPG, BMP, Animated GIF), and recover recent session backups. The Save section has been split into partials to support different environments, offering 'Save in Browser' for offline storage, 'Save as File' for desktop mode, and 'Save as .piskel' for file downloads, alongside sprite metadata fields like title and description. The Preferences section remains organized into tabs for Misc, Grid, and Tile mode settings.
src/templates/settings · high confidence
Unified storage service with Ctrl+S support and IndexedDB migration
The application now features a central StorageService that unifies save operations across desktop, local browser storage, IndexedDB, and gallery backends. This change introduces a global Ctrl+S shortcut that intelligently saves to the gallery if logged in, to the desktop if running in Node-Webkit, or to IndexedDB otherwise. It also adds an isSaving state to prevent concurrent saves and migrates local browser saves from LocalStorage to IndexedDB for better performance and capacity.
src/js/service/storage · high confidence
Updated Spectrum colorpicker to v1.1.2 with palette and format enhancements
The Spectrum colorpicker library in src/js/lib/spectrum has been updated to version 1.1.2. This update introduces a new \preferredFormat\ option, allowing users to control the color format displayed in the picker's input field, and enhances the palette feature by supporting the download of custom color palettes. The change also includes internal cleanup and fixes to ensure consistent RGB formatting.
src/js/lib/spectrum · high confidence
Updated and added vector icon assets
The \misc/icons\ directory has been updated with new and revised Adobe Illustrator source files (\.ai\) for several UI elements, including the eraser, mirror, rectangle, and rectangle selection tools. These changes refresh the visual assets used in the application's interface.
misc/icons · medium confidence
Updated deployment scripts for piskel-web and piskel-website
The bin directory now contains new Node.js scripts (copy-to-piskel-web.js and copy-to-piskel-website.js) to handle static file deployment. The piskel-web script copies production assets to the sprite editor and kids folders, replacing default index.html files with specific partials and cleaning up unused partial directories. The piskel-website script copies statics to the main website's editor directory, handling the migration of the main-partial.html file and ensuring the previous version is removed before copying the new one.
bin · high confidence
Fixes
Fix backward compatibility deserializers to use correct FPS constant
The backward compatibility deserializers for animation formats v0 and v1 have been updated to correctly reference the FPS constant. Previously, the code referenced \Constants.DEFAULTS.FPS\, which has been corrected to \Constants.DEFAULT.FPS\ in both \Deserializer\_v0.js\ and \Deserializer\_v1.js\. This ensures that animations loaded from older file formats are initialized with the correct frames-per-second setting, preventing potential playback speed issues for users importing legacy projects.
src/js/utils/serialization/backward · high confidence
Test coverage
Added GIF test cases for color and transparency edge cases; Added Selenium IDE test cases for UI interactions; Added drawing test data fixtures for e2e testing; Added unit tests for core application components.
Dependencies
Add Bootstrap tooltip styling and core library dependencies
The application now includes custom CSS overrides for Bootstrap tooltips (increasing opacity and line-height) and bundles the necessary client-side libraries: Bootstrap v2.1.1 (tooltip component only), jQuery v1.8.0, jQuery UI v1.10.3 (core, widget, mouse, sortable), and JSZip for archive generation. A custom iframe loader utility is also added to handle template injection, and the main index.html is updated to include these resources and the piskel-boot script.
src · high confidence
Initial package.json and lockfile for Piskel 0.15.2-SNAPSHOT
This change introduces the foundational dependency manifest (package.json) and its lockfile (package-lock.json) for the Piskel pixel art editor at version 0.15.2-SNAPSHOT. It establishes the project's build and runtime environment by defining core dependencies like minimist and a comprehensive set of devDependencies including Vite 8.0.7 for building, Biome 2.4.10 for linting, Playwright 1.59.1 for end-to-end testing, Karma 6.3.4 for unit tests, and nw-builder 4.17.5 for desktop application packaging. The entry also configures standard scripts for building, linting, testing, and releasing the application.
(dependencies) · high confidence
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 43 → 36 (-7.1)
- Rubric changed (rubric-2026.09.12 → rubric-2026.09.18) — scores are not directly comparable.
Lenses
- Code Health 71 → 58 (-12.2)
- Architecture 100 → 84 (-16.1)
- Maturity 53 → 51 (-2.5)
- Readiness 35 → 28 (-7.4)
- Security 60 → 67 (+6.8)
- Accessibility 36 → 27 (-9.6)
- Performance 60 (new)
Resolved (7)
- Dependency hygiene PARTLY measured — npm pinning read, dependency currency not (no pnpm-resolved versions to grade)
- Documentation: no contributor guidance (README.md)
- High CVE: [GHSA redacted] (package-lock.json)
- High CVE: [GHSA redacted] (package-lock.json)
- High CVE: [GHSA redacted] (package-lock.json)
- High CVE: [GHSA redacted] (package-lock.json)
- Off-boarding risk: anonymized user #1
New (157)
- (anonymous) (cognitive 16) (src/js/database/BackupDatabase.js)
- (anonymous) (cognitive 16) (src/js/utils/Base64.js)
- (anonymous) (cognitive 16) (src/js/utils/Dom.js)
- (anonymous) (cognitive 16) (src/js/worker/imageprocessor/ImageProcessorWorker.js)
- (anonymous) (cognitive 18) (src/js/controller/preview/PreviewController.js)
- (anonymous) (cognitive 20) (src/js/utils/CanvasUtils.js)
- (anonymous) (cognitive 21) (src/js/tools/drawing/selection/BaseSelect.js)
- (anonymous) (cognitive 21) (src/js/utils/Template.js)
- (anonymous) (cognitive 21) (src/js/utils/core.js)
- (anonymous) (cognitive 24) (src/js/controller/preview/PreviewActionsController.js)
- (anonymous) (cognitive 24) (src/js/service/HistoryService.js)
- (anonymous) (cognitive 26) (src/js/controller/dialogs/importwizard/ImportWizard.js)
- (anonymous) (cognitive 26) (src/js/lib/jquery-ui-1.10.3.custom.js)
- (anonymous) (cognitive 29) (src/js/controller/FramesListController.js)
- (anonymous) (cognitive 32) (src/js/controller/dialogs/importwizard/steps/ImageImport.js)
- (anonymous) (cognitive 32) (src/js/selection/SelectionManager.js)
- (anonymous) (cognitive 38) (src/js/controller/LayersListController.js)
- (anonymous) (cognitive 38) (src/js/controller/piskel/PiskelController.js)
- (anonymous) (cognitive 47) (src/js/utils/PixelUtils.js)
- (anonymous) (cognitive 49) (src/js/controller/DrawingController.js)
- …and 137 more
Changes since last survey
- 8 commits — 8 feature/other, 0 fixes
By area
- src/js — 6 commits
- (root) — 1 commit
- .husky/pre-commit — 1 commit
Notable commits
- change: Enforce npm run lint, do not run (yet) on all staged files like karma tests which are not biomejs compliant
- change: Migrate all Q.js usage
- change: Remove IE11 GIF worker specific code
- change: Remove Q.js deps
- change: Remove ie11 code from temaplte.js
- change: Remove ie11 specific classlist toggle workaround
- change: Remove isIE11 from useragent util
- change: Remove obsolete APIs window.msSaveBlob and window.saveBlob
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
piskelapp/piskel was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 1 October 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit bef52beb312e771bf0cbb915d873e8d638842d7a — the exact code this score is about.
- Scored under rubric-2026.09.18 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-e569280dd5e2.