Skip to content

matheoheo/LPCFramesAnalyzer

Repository files navigation

LPC Frames Analyzer - Fast animation extraction.

LPC Frames Analyzer is a tool built for 2D game developers who want to speed up their workflow when working with spritesheets generated using the LPC Character Generator. It focuses on one thing: making extraction quick and clean.


Application interface preview

Why did i develop it?

The LPC Generator is an amazing tool - especially, if you don't have time or skills to create character art from scratch. It makes getting started incredibly easy.

But once i began using it in real project, i ran into a frustrating issue:

Some animations don't fit perfectly into the standard 64x64 frame size, which causes visible shifting when played in-game.

The following gifs illustrate the problem:

Default (visible jittering) Analyzed (steady in place)
GIF_Default GIF_Analyzed

As you can see - after the image is analyzed - the animation stays in place.

So what does this tool actually do?

LPC Frames Analyzer automatically detects frames (both those that fit into 64x64 standard grid, as well as oversized ones) and applies positional offsets to ensure that every animation stays visually stable.

Instead of manually adjusting each frame, the tool analyzes the entire spritesheet and corrects aligment issues in a consistent, and predictable way.

This allows you to:

  • eliminate animation jitter
  • keep characters visually anchored
  • save hours of manual tweaking.

Key Features

Hybrid Frame Detection - The tool combines fixed-grid detection with an intelligent pixel scanner. It's smart enough to handle standard 64x64 cycles, as well as oversized 'special' frames like spear thrusts or sword swinging in one go.

📐 Pixel Perfect Alignment - The tool doesn't just cut images; it understands them. It automatically detects offsets of each frame that keeps your character anchored, even when the sprite size changes.

🛠️ Granular Control - While the automation is powerful, you are always in charge. You can manually override offsets, adjust 'starting points' or change scanner precision to handle your spritesheets.

🎬 Instant Visual Feedback - Features built-in animation player. You can view your processed clips at full speed or frame-by-frame to catch any alignment issues before you even touch a single line of code.

🚀 Batch Processing - Select an entire directory of spritesheets and analyze them all at once. The tool will queue them up and process everything in one go.

💾 Flexible Export Options - Save results in universal JSON format for maximum compatability.

Tech Stack

This project was built using the following technologies and libraries:

  • C++ 20: core language and standard library.
  • SFML: window management, handling graphics.
  • ImGui-SFML: integration of Dear ImGui for SFML to provide Graphical User Interface.
  • nlohmann/json: JSON Parsing & exporting.
  • GoogleTest: unit testing.
  • CMake: build system to configure and link the project and its dependencies.

CMake / Building

The project uses CMake for simple, cross-platform building so the project can be initialized with minimal setup. You must not worry about downloading manually any packages, as if you follow this steps, everything will be fetched by git & cmake automatically.

  1. Open command terminal (cmd)
  2. Navigate to directory where you want to clone the project (cd C:/Projects)
  3. Clone the repository (git clone --recurse-submodules https://github.com/matheoheo/LPCFramesAnalyzer.git)
  4. Enter the project folder (cd LPCFramesAnalyzer)
  5. Create build directory and navigate there (mkdir build && cd build)
  6. Configure the project (cmake ..)
  7. Build the project (cmake --build .) | Results in debug build | For release build, please use: (cmake --build . --config Release)

Running application

To start the application from command terminal, you must build target: cmake --build . --target LPCAnalyzer. Then you can navigate to Debug folder and run the app cd Debug && LPCAnalyzer.exe.

Other Targets

You can also build additional targets such as examples and tests.

cmake --build . --target LPCJsonExample
cmake --build . --target LPCMattExample
cmake --build . --target LPCTests

After building, the executables will by located in build directory (Debug/ or Release/ folders, depending on your configuration)

Downloads

If you don't want to build the application, you can just download the released version from this link

Tutorial

I believe, that using this application is straightforward. This following section will explain it to you, so you can start quickly.

  1. The Spritesheet

    First thing you need to have is a generated spritesheet using this website. (I have also included basic generated spritesheets in the 'assets' directory if you just wanna see how this tool works)

  2. The application

    When you open the application, you will be greeted in the Menu section - this one is very minimalistic. All you have to do is just click Start Analyzer.


    Main Menu

  3. Importing

    First step, in our process is to select spritesheets that we want to analyze. For that, you just need to type a path to directory with your files and select them from list.


    Importing sheets.

  4. Calibration

    In this step, you can calibrate settings which impact the algorithm.


    Calibrating.

    Here are explainations for each option:

    a) Analysis Mode

    • Classic Grid: The algorithm will only process frames that are size of 64x64 - those, that fit in the standard grid. It will stop, when the grid turns into 'oversized' frames.
    • Dynamic Scanner: The Spritesheet Processor will only scan for frames that are different than standard ones (like sword slash, or other).
    • Full Processor: Hybrid approach. It will scan the whole image with both of those ways. Recommended one.

    b) Scanner Precision - those are important only for dynamic scanning.

    • Horizontal Search Limit: This is a distance between frames in a single row (in X axis).
    • Vertical Jump Limit: This is a distance between rows of frames (in Y Axis).
Horizontal Limit Vertical Limit
Horizontal Serach Limit Image Vertical Jump Limit Image

In most cases, the default values of 180 are good enough.

c) Starting Point - this settings are the essential part of algorithm. The detection of dynamic position is very important, because it determines where the Classic Grid ends and Dynamic Scanner starts.

This illustration shows where is this point.


Grid Break Point.

The area inside rectangle are all valid points for this position. Algorithm will detect it for you, but if detection point is not how it is supposed to be, then user can also specify it themselves.

You can always preview the spritesheet while calibrating to determine the best settings for you specific spritesheet.

  1. Output and Exporting

    In the final stage, you can preview all selected spritesheets and their animations.

    Use the Preview section to play animations and verify they remain stable.

    If something doesn't look right, the Frame Inspector allows you to manually adjust position, size and offsets for individual frames.

    You can also tweak animation speed using Frame Time, or disable offset to compare the before/after result.


Result Stage.

Export Options

Once your animations are done, and look correct you can export the results in two different formats depending on your needs.

Native format (.matt)

This is default format used by LPC Frames Analyzer. It's structure, and parsing is handled by my seperate project, which you can explore here: Marser

JSON Format

The JSON export is added for maximum compatibility.

It does not depend on any specific parser - you can read and process it using standard JSON libraries in your project.

Both formats are equally good and present the same data.

Using exported data

Once the data is exported, integrating it into your project is straightforward.

JSON Example

You can parse JSON file using any standard library. For this example, i have used nlohmann/json:

#include <sfml/Graphics.hpp>
#include <nlohmann/json.hpp>
#include <fstream>
#include <iostream>

struct FrameRect
{
	sf::IntRect rect;
	sf::Vector2i offset;
};

struct Animation
{
	std::string name;
	std::string direction;
	std::vector<FrameRect> frames;
};

//This function shows, how You can implement a functionality to load result animations from json file.
std::vector<Animation> jsonParseFile(const std::filesystem::path& path)
{
	std::ifstream file(path);
	if (!file)
	{
		std::cout << "Failed to open .json file\n";
		return {};
	}
	nlohmann::json j;
	file >> j;

	std::vector<Animation> result;

	for (const auto& anim : j["animations"])
	{
		auto& thisAnim = result.emplace_back();
		thisAnim.name = anim["name"];
		thisAnim.direction = anim["dir"];

		for (const auto& framesList : anim["frames"])
		{
			const auto& fRect = framesList["rect"];
			const auto& fOffset = framesList["offset"];
			sf::IntRect rect(
				{ fRect["x"].get<int>(), fRect["y"].get<int>() },
				{ fRect["w"].get<int>(), fRect["h"].get<int>() });

			sf::Vector2i offset(fOffset["x"], fOffset["y"]);
			thisAnim.frames.push_back({ .rect = rect, .offset = offset });
		}
	}

	return result;

}

MATT example

The .matt format is handled by a dedicated parser. Firstly, you need to integrate Marser to your project. The format, in itself is very similar to the json one. Following code illustrates how to parse .matt result.

#include <sfml/Graphics.hpp>
#include <matt/parser/Parser.h>

struct FrameRect
{
	sf::IntRect rect;
	sf::Vector2i offset;
};

struct Animation
{
	std::string name;
	std::string direction;
	std::vector<FrameRect> frames;
};

//This function shows, how You can implement a functionality to load result animations from matt file.
std::vector<Animation> mattParseFile(const std::filesystem::path& path)
{
	std::vector<Animation> result;
	matt::parser::Value root = matt::parser::Parser::parseFile(path);
	
	for (auto& anim : root["animations"].asList())
	{
		auto& thisAnim = anim.asMap();
		auto& newAnim = result.emplace_back();

		newAnim.direction = thisAnim["dir"].asString();
		newAnim.name = thisAnim["name"].asString();

		auto& framesList = thisAnim["frames"].asList();
		for (auto& frame : framesList)
		{
			auto& val = frame.asMap();
			sf::IntRect rect(
				sf::Vector2i(val["rect"]["x"].asInt(), val["rect"]["y"].asInt()),
				sf::Vector2i(val["rect"]["w"].asInt(), val["rect"]["h"].asInt()));
			sf::Vector2i offset(val["offset"]["x"].asInt(), val["offset"]["y"].asInt());
			newAnim.frames.push_back({ .rect = rect, .offset = offset });
		}	
	}

	return result;
}

Limitations

While LPC Frames Analyzer is designed to handle most LPC spritesheets reliably, there are some known limitations.

Sometimes the offset calculation might be mismatched with expected values and cause shifting mid-animation anyway like in the following example:

Analyzed Offset
Limitation Broken offset

As you can see, even after processing the Spritesheet, some of the frames are misaligned (gif on the left). The offset is wrong which causes shifting.

It occurs when a character holds a weapon (like sword or staff) that extend below the character's feet during an animation frame. In this case, the algorithm might mistakenly treat the weapon position as anchor point, which leads to wrong offset.

The good news is, that you can easily fix it by playing with offset values and finding the correct one.

Fixed Proper offset
Fixed Limitation Offset fixed

The LPC Frame Analyzer is tested only on spritesheets created by this generator. Using any other generators that are not identical to this one's format will most probably cause failures.

Notes

The credits for usage of the spritesheet that was used as an example in Tutorial section can be found here

Credits for the spritesheet used in Limitations is available here

License

The project is licensed under MIT License - full text available in LICENSE

Future Plans

Smart Animation Naming: Automatically assign default names to animations based on their position in LPC Sheet (e.g., "Walk", "Slash"), so you do not have to rename them manually.

Better Directional Sorting: Improved logic for grouping animations by direction.

CLI Support: I'm planning to add a Command Line Interface version to automate processing of hundreds of spritesheets at once using scripts.

About

Tool for analyzing LPC-generated spritesheets. Automatically detects frames and offsets, exports to JSON for 2D Game Devs.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors