[ Prev | Index | Next ]
Japanese English
Now Loading...
Download
Please download on PC (not smartphone) and extract the ZIP file. Then double-click VCSSL.bat (batch file) to execute for Microsoft® Windows®, or execute VCSSL.jar (JAR file) on the command line for Linux® and other OSes.
For details, see How to Use.
You are free to use and modify this program and material, even for educational or commercial use. » Details

Simple Tool for Animating Sequential Images

This program is a lightweight tool developed with VCSSL that allows you to play back sequential image files (in PNG or JPEG format) as an animation without converting them into a video file.

Here, "sequential image files" refers to image files with filenames that include consecutive numbers at the end, such as: image1.png, image2.png, image3.png, ..., image100.png.

- Table of Contents -

How to Use

Download and Extract

At first, click the "Download" button at the above of the title of this page by your PC (not smartphone). A ZIP file will be downloaded.

If you are using Windows, right-click the ZIP file and choose "Properties" from the menu, and enable "Unblock" checkbox at the right-bottom (in the line of "Security") of the properties-window. Otherwise, when you extract the ZIP file or when you execute the software, security warning messages may pop up and the extraction/execution may fail.

Then, please extract the ZIP file. On general environment (Windows®, major Linux distributions, etc.), you can extract the ZIP file by selecting "Extract All" and so on from right-clicking menu.

» If the extraction of the downloaded ZIP file is stopped with security warning messages...

Execute this Program

Next, open the extracted folder and execute this VCSSL program.

For Windows

Double-click the following batch file to execute:

VCSSL__Double_Click_This_to_Execute.bat

For Linux, etc.

Execute "VCSSL.jar" on the command-line terminal as follows:

cd <extracted_folder>
java -jar VCSSL.jar

» If the error message about non-availability of "java" command is output...

If You Run Out of Memory While Running the Program...

Depending on how you use it, this program may consume a considerable amount of memory. As a result, the default memory allocation may not be sufficient in some cases. If you encounter such issues, please refer to the following:

» When You Run Out of Memory While Running the Program (for Microsoft® Windows® Users)
» When You Run Out of Memory While Running the Program (for Linux® and Other OS Users

Selecting the Input Folder

Next, you'll be asked whether you want to specify the input folder (i.e., the folder containing the sequential image files you want to animate). If you do want to specify a folder, click "Yes", then choose the location of the folder.

If you click "No" to skip this step, the tool will automatically use the folder named "sample" inside the folder where the program was extracted or downloaded. This folder contains sample sequential images, so if this is your first time trying out the tool, it’s recommended to click "No" here.

The window to select the input folder

Entering the File Name

You will then be prompted to enter the file name.

File Name Input Window

In the file name input window, you only need to enter the part of the filename excluding the sequential number and extension. For example, if your image files are named like "image123.png", enter just the "image" part.

Selecting the File Extension

Next, you'll be asked to select the file extension. Choose either ".png" for PNG format or ".jpg" for JPEG format. As of now, these are the only two formats supported by this tool.

Extension select window

Choosing Whether to Buffer Image Data

Finally, you'll be asked whether you want to buffer the image data. Unless you encounter memory-related errors, it's generally recommended to select "Yes".

Buffering enable/disable window

Buffering affects how and when image files are read.

When buffering is enabled, all image data is loaded into memory at the beginning, and the animation is played using that data.

When buffering is disabled, image files are loaded one by one as needed, and each image is discarded from memory after it is shown.

Buffering typically results in smoother animations (especially on the first loop). It also reduces stress on storage devices, which is useful if you're running the animation repeatedly on a machine with an older HDD.

However, buffering requires more memory, so if the images are large or numerous, it may cause the program to terminate due to insufficient memory. In such cases, disabling buffering can help conserve memory usage.

Using the Image Viewer Window

Once all inputs are completed, an image viewer window will appear, and the animation playback will begin automatically.

The image display window

The controls are similar to those of a standard video player.

You can toggle playback using the "PLAY / STOP" button in the lower-left corner, and use the seek bar (the long slider at the bottom) to jump to any point in the animation.

In the "Image Interval (ms)" field, you can specify the delay (in milliseconds) between one image and the next. Larger values result in slower playback speed.

Code

This program is written in VCSSL.

If you want to modify or customize the tool, you can simply open the program file "ImageFileAnimator.vcssl" in a text editor and make changes directly.

Since VCSSL is a scripting language, no recompilation is required. Its syntax is simple and C-like, so if you have any experience with C or similar languages, you should be able to understand most of it intuitively.

Entire Code

This is more of a practical tool than just a sample script, so the code is a bit lengthy and includes some ad-hoc handling in various parts. Because of that, instead of explaining the code line by line from the top, we'll simply provide the full source code here.

If you'd like to understand how it works in detail, it's recommended to start reading from the main function and follow the logic step by step. Refer to the comments in the code as needed, and dive into the lower-level functions along the way.

Please note that this is a standalone, quick-and-dirty tool, so there are quite a few hardcoded values throughout the script-including parts of the GUI layout. We hope you'll forgive the lack of polish in those areas.

Here is the complete source code of the tool:


coding UTF-8;  // Specify character encoding (to prevent mojibake)

// Import libraries
import GUI;         // Library for GUI components like windows and buttons
import Graphics;    // Library for handling image data and graphic resources
import Graphics2D;  // Library for 2D rendering
import File;        // Library for handling file and folder information
import system.Int;  // Library providing helper functions for integers


// Constant settings for GUI
const int DEFAULT_WINDOW_WIDTH = 800;  // Initial window width
const int DEFAULT_WINDOW_HEIGHT = 700; // Initial window height
const int CONTROL_AREA_HEIGHT = 60;    // Height of the control section at the bottom of the window
const int PLAY_BUTTON_WIDTH = 140;     // Width of the play/stop button
const string PLAY_TEXT = "PLAY";       // Label text for the play button
const string STOP_TEXT = "STOP";       // Label text for the stop button
const int BACKGROUND_COLOR[] = { 50, 50, 50, 255 }; // Background color (R,G,B,Alpha)

// Constant settings for file paths
const string DEFAULT_DIRECTORY_PATH = "./sample"; // Default folder path
const string DEFAULT_FILE_NAME = "image"; // Default image file name (excluding number and extension)
const string FILE_EXTENSION_SELECT_MESSAGE = "- Select Extension -"; // Message shown when selecting file extension
const string FILE_EXTENSIONS[] = { FILE_EXTENSION_SELECT_MESSAGE, ".png", ".jpg" }; // Extension options

// Other constant settings
const int DEFAULT_WAIT = 30; // Default interval between frames (milliseconds)
const int FILE_NUMBER_SEARCH_LIMIT = 1000; // Max number to search for start of sequence

// Variables related to file names and paths (set in the configure function)
string directoryPath; // Path to the folder containing image files
string fileNameHead;  // File name prefix (excluding number and extension)
string extension;     // File extension (including dot)
int fileNumberBegin;  // Starting number of the sequence
int fileNumberEnd;    // Ending number of the sequence

// Variables related to GUI layout
int windowWidth = DEFAULT_WINDOW_WIDTH;   // Width of the image display window (can change)
int windowHeight = DEFAULT_WINDOW_HEIGHT; // Height of the image display window (can change)
int screenWidth;   // Width of the display screen (set in the "configure" function)
int screenHeight;  // Height of the display screen (set in the "configure" function)

// Variables for GUI components
int screenWindow = NULL;     // ID of the image display window
int screenImageLabel = NULL; // ID of the image display label
int screenGraphics = NULL;   // ID of the graphics resource for drawing on the screen
int screenRenderer = NULL;   // ID of the renderer (drawing engine) for the screen
int playButton = NULL;  // ID of the play/stop button
int seekSlider = NULL;  // ID of the seek bar
int waitField = NULL;   // ID of the field for setting frame interval
int seekLabel = NULL;   // ID of the label next to the seek bar
int waitLabel = NULL;   // ID of the label next to the interval input field

// Variables related to images
int totalNumberOfImages;    // Total number of image files
string imageFilePaths[];    // Array to store paths of all image files
int imageGraphicsBuffers[]; // Array to buffer image contents (stores graphics resource IDs for each image)

// Variables for control
bool continuesMainLoop = true;  // Controls whether the main loop continues (set to false to exit)
bool windowSizeChanged = false; // Set to true when the window is resized, triggers re-layout
bool playing = true;            // True when playing, false when stopped
bool bufferingEnabled;          // Controls whether image buffering is enabled (set in the configure function)


// ============================================================
// Main process - This function runs automatically on startup
// ============================================================

void main() {
	
	// Perform configuration based on user input
	configure();
	
	// Initialize drawing-related resources
	initializeGraphicsResources();
	
	// Initialize GUI components
	initializeGUI();
	
	// Apply layout settings to the GUI
	updateLayout();
	
	// Once the image window is open, hide the CUI console window to avoid clutter
	hide();
	
	// Variable to store the last displayed image index, to avoid redundant redraws
	int lastImageIndex = -1;
	
	// Main loop: updates and redraws the image on each cycle
	while (continuesMainLoop) {
		
		// Get the image index to display, based on the seek bar's position
		int imageIndex = getComponentInt(seekSlider);
		
		// Draw the image on the screen (skip if the image hasn't changed)
		if (imageIndex != lastImageIndex) {
			drawScreen(imageIndex);
		}
		
		// Handle window resize
		if (windowSizeChanged) {    // This variable is set to true in "onWindowResize" when a resize is detected
			updateLayout();         // Reapply GUI layout
			drawScreen(imageIndex); // Redraw image on screen
			windowSizeChanged = false; // Reset resize flag
		}
		
		// Store the index of the last drawn image
		lastImageIndex = imageIndex;
		
		// Wait for the specified interval before the next frame (animation delay)
		int wait = getWaitValue();
		sleep(wait);
		
		// Advance time if animation is playing
		if (playing) {
			
			// Increment image index; loop back to start if at the end
			imageIndex++;
			if (imageIndex == totalNumberOfImages) {
				imageIndex = 0;
			}
			
			// Update the seek bar to match the new image index
			setComponentInt(seekSlider, imageIndex);
		}
	}
	
	// Exit the program when the main loop ends
	exit();
}


// ==================================================
// Function for handling configuration via user input
// ==================================================

void configure() {
	
	// Select the folder to load image files from (if skipped, the "sample" folder is used)
	directoryPath = DEFAULT_DIRECTORY_PATH;
	if (confirm("Do you want to specify the folder for loading images?", "(If you select 'No', the '" + DEFAULT_DIRECTORY_PATH + "' folder will be used)")) {
		directoryPath = choose("Select the folder to load images from", ".");
	}
	println("Image folder = " + directoryPath);
	
	// Enter the file name (excluding number and extension)
	fileNameHead = input("Enter the image file name (excluding number and extension)", DEFAULT_FILE_NAME);
	println("Image file name = " + fileNameHead);
	
	// Select the file extension
	extension = select(FILE_EXTENSIONS);
	while (extension == FILE_EXTENSION_SELECT_MESSAGE) {
		extension = select(FILE_EXTENSIONS);
	}
	println("Extension = " + extension);
	
	// Search for image files in the folder and determine the start and end of the sequence
	scanFileIndex();
	
	// Choose whether to enable image buffering
	bufferingEnabled = confirm(
		"Enable image buffering?",
		"Buffering helps animations play more smoothly.",
		"It also reduces stress on HDDs, especially on older PCs.",
		"However, buffering uses more memory, which may cause issues in low-memory environments."
	);
}


// ==================================================================================
// Function to search for image files and determine the start and end of the sequence
// ==================================================================================

void scanFileIndex() {
	
	println("Searching for files...");
	
	// Search for the starting number and set it to "fileNumberBegin"
	fileNumberBegin = 0;
	while (true) {
		
		// Starting from 0, increment fileNumberBegin by 1 and
		// check if a file with that number exists;
		// the first one found will be considered the start of the sequence
		
		string fileName = fileNameHead + fileNumberBegin + extension;
		string filePath = getFilePath(fileName, directoryPath);
		if (exists(filePath)) {
			println("Start file: " + filePath);
			break;
		}
		
		if(fileNumberBegin >= FILE_NUMBER_SEARCH_LIMIT) {
			popup("Searched up to file number " + FILE_NUMBER_SEARCH_LIMIT + " but no sequential file was found.");
			exit();
		}
		
		fileNumberBegin++;
	}
	
	
	println("Start number = " + fileNumberBegin);
	
	// Search for the ending number and set it to fileNumberEnd
	fileNumberEnd = fileNumberBegin;
	while (true) {
		
		// Starting from fileNumberBegin, increment fileNumberEnd by 1
		// and check if a file with that number exists;
		// when no such file is found, set (current number - 1) as the end of the sequence
		
		string fileName = fileNameHead + fileNumberEnd + extension;
		string filePath = getFilePath(fileName, directoryPath);
		if (!exists(filePath)) {
			fileNumberEnd--;
			break;
		}
		fileNumberEnd++;
	}
	
	println("End number = " + fileNumberEnd);
}


// ==================================================
// Initialization for rendering-related resources
// ==================================================

void initializeGraphicsResources() {
	
	// Calculate and set the total number of image files
	totalNumberOfImages = fileNumberEnd - fileNumberBegin + 1;
	
	// Allocate arrays for file paths and buffers, using the total image count
	alloc(imageFilePaths, totalNumberOfImages);
	alloc(imageGraphicsBuffers, totalNumberOfImages);
	
	// Store the full file paths in the array
	for (int i=0; i<totalNumberOfImages; i++) {
		string fileName = fileNameHead + (fileNumberBegin + i) + extension;
		imageFilePaths[i] = getFilePath(fileName, directoryPath);
	}
	
	// If buffering is enabled,
	// load all image files in advance and create graphics resources,
	// then store them in the buffer array
	if (bufferingEnabled) {
		for (int i=0; i<totalNumberOfImages; i++) {
			println("Preparing image buffer: " + imageFilePaths[i]);
			imageGraphicsBuffers[i] = newGraphics(imageFilePaths[i]);
		}
		println("Image buffer preparation complete");
	}
	
	// Create the graphics resource and renderer (drawing engine) for the screen
	screenGraphics = newGraphics();
	screenRenderer = newGraphics2DRenderer(1, 1, screenGraphics); // 幅や高さはupdateLayout関数で再設定
}


// ==================================================
// Initialization for screen (GUI) components
// ==================================================

void initializeGUI() {
	
	// Create the image display window
	screenWindow = newWindow(0, 0, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, "Image File Animator");
	
	// Create the image display label and place it in the window
	screenImageLabel = newImageLabel(0, 0, 0, 0, screenGraphics); // Width and height will be updated in updateLayout()
	mountComponent(screenImageLabel, screenWindow);
	
	// Create the play/stop button and place it in the window
	playButton = newButton(0, 0, 0, 0, STOP_TEXT); // Width, height, and position will be set in updateLayout()
	setComponentFontSize(playButton, 20);
	mountComponent(playButton, screenWindow);
	
	// Create the seek bar (horizontal slider) and place it in the window
	seekSlider = newHorizontalSlider(0, 0, 0, 0, 0, 0, totalNumberOfImages-1); // Same for width, height, and position
	mountComponent(seekSlider, screenWindow);
	
	// Create the info label to the left of the seek bar and place it in the window
	seekLabel = newTextLabel(0, 0, 0, 0, ""); // Same for width, height, and position
	mountComponent(seekLabel, screenWindow);
	
	// Create the interval (wait time) input field and place it in the window
	waitField = newTextField(0, 0, 0, 0, (string)DEFAULT_WAIT); // Same for width, height, and position
	mountComponent(waitField, screenWindow);
	
	// Create the label next to the interval input field and place it in the window
	waitLabel = newTextLabel(0, 0, 0, 0, "Update Interval (ms) ="); // Same for width, height, and position
	mountComponent(waitLabel, screenWindow);
}


// =======================================================
// Function to get the user-specified interval (wait time)
// =======================================================

int lastWait = -1; // Store the previous value to avoid duplicate warning messages
int getWaitValue() {
	
	// Get the value from the wait time input field as a string
	string waitText = getComponentString(waitField);
	
	// If the input is not a valid integer, wait briefly and try again (in case the user is editing)
	while (!isInt(waitText)) {
		waitText = getComponentString(waitField);
		sleep(100);
	}
	
	// If the value starts with 0 and has more than one digit, remove the leading zero
	// (to avoid interpretation as old-style octal literals, which are deprecated and may trigger warnings)
	while (countText(waitText) >= 2 && checkText(waitText, "0", Text.START)) {
		waitText = replaceText(waitText, "0", "", Text.FIRST);
	}
	
	// Convert the string to an integer, and show a warning if the value is unusually large
	int wait = (int)waitText;
	if (wait >= 10000 && wait != lastWait) {
		if( !confirm("A large value (10 seconds or more) is specified for the interval. Are you sure you want to apply it?") ) {
			waitText = (string)DEFAULT_WAIT;
			setComponentText(waitField, waitText);
			wait = DEFAULT_WAIT;
		}
	}
	
	// Store the value that triggered a warning, to skip future warnings for the same value
	lastWait = wait; 
	
	return wait;
}


// ============================================================
// Function to handle layout of GUI components on the screen
// ============================================================

void updateLayout() {
	
	// Get the inner size of the window and calculate the display area size
	int windowInnnerSize[] = getComponentSize(screenWindow, INNER);
	screenWidth = windowInnnerSize[0];
	screenHeight = windowInnnerSize[1] - CONTROL_AREA_HEIGHT;
	
	// Update the renderer and image label with the new screen size
	setGraphics2DSize(screenRenderer, screenWidth, screenHeight);
	setComponentSize(screenImageLabel, screenWidth, screenHeight);
	
	// Layout settings for the control panel at the bottom of the window
	
	// Play/stop button
	setComponentSize(playButton, PLAY_BUTTON_WIDTH, CONTROL_AREA_HEIGHT);
	setComponentLocation(playButton, 0, screenHeight);
	
	// Seek bar
	setComponentSize(seekSlider, screenWidth - PLAY_BUTTON_WIDTH - 180, 20);
	setComponentLocation(seekSlider, PLAY_BUTTON_WIDTH + 160, screenHeight + 10);
	
	// Wait time input field
	setComponentSize(waitField, 100, 20);
	setComponentLocation(waitField, PLAY_BUTTON_WIDTH + 160, screenHeight + 30);
	
	// Info label to the left of the seek bar
	setComponentSize(seekLabel, 140, 20);
	setComponentLocation(seekLabel, PLAY_BUTTON_WIDTH + 20, screenHeight + 10);
	
	// Description label to the left of the wait time input
	setComponentSize(waitLabel, 140, 20);
	setComponentLocation(waitLabel, PLAY_BUTTON_WIDTH + 20, screenHeight + 30);
	
	// Repaint the labels
	paintComponent(seekLabel);
	paintComponent(waitLabel);
}


// ==================================================
// Function to draw an image on the screen
// ==================================================

void drawScreen(int i) {
	
	// Declare a variable to store the ID of the graphics resource for the image
	int imageFileGraphics;
	
	// If buffering is enabled, use the preloaded graphics resource
	if (bufferingEnabled) {
		imageFileGraphics = imageGraphicsBuffers[i];
	
	// If buffering is disabled, load the image from the file path and create a graphics resource
	} else {
		imageFileGraphics = newGraphics(imageFilePaths[i]);
	}
	
	// Get the width and height of the image
	int imageWidth = getGraphicsWidth(imageFileGraphics);
	int imageHeight = getGraphicsHeight(imageFileGraphics);
	
	// Calculate the aspect ratio of the image
	float imageAspectRatio = (float)imageWidth / (float)imageHeight;
	
	// Calculate the width and height to draw the image, fitting it to the screen while preserving aspect ratio
	int drawWidth = screenHeight * imageAspectRatio;
	int drawHeight = screenHeight;
	if (drawWidth > screenWidth) {
		drawWidth = screenWidth;
		drawHeight = screenWidth / imageAspectRatio;
	}
	
	// Calculate the top-left corner position to center the image on the screen
	int drawX = screenWidth/2 - drawWidth/2;
	int drawY = screenHeight/2 - drawHeight/2;
	
	// Fill the screen with the background color
	setDrawColor(screenRenderer, BACKGROUND_COLOR);
	drawRectangle(screenRenderer, 0, 0, screenWidth, screenHeight, true);
	
	// Draw the image on top of the background
	drawImage(screenRenderer, drawX, drawY, drawWidth, drawHeight, imageFileGraphics);
	int imageNumber = getComponentInt(seekSlider) + fileNumberBegin;
	setComponentString(seekLabel, "Image Number=" + imageNumber);
	
	// Repaint the image display label
	paintComponent(screenImageLabel);
	
	// If buffering is disabled, delete the graphics resource after each draw
	if (!bufferingEnabled) {
		deleteGraphics(imageFileGraphics);
	}
}


// ============================================================
// Function called when a button is clicked (event handler)
// ============================================================

void onButtonClick(int id) {
	
	// If the play/stop button is clicked
	if (id == playButton) {
		
		// Toggle between playing and stopped states
		playing = !playing;
		
		// Update the button label accordingly
		if (playing) {
			setComponentString(playButton, STOP_TEXT);
		} else {
			setComponentString(playButton, PLAY_TEXT);
		}
	}
}


// ============================================================
// Function called when the window is resized (event handler)
// ============================================================

void onWindowResize(int id, int width, int height) {
	
	// If the image display window is resized
	if (id == screenWindow) {
		
		// Set the resize flag to true to trigger layout update in the main loop
		// (Avoid heavy processing here since resize events may fire repeatedly)
		windowSizeChanged = true;
	}
}


// ============================================================
// Function called when the window is closed (event handler)
// ============================================================
void onWindowClose (int id) {
	
	// If the image display window is closed
	if (id == screenWindow) {
		
		// Exit the main loop and end the program
		continuesMainLoop = false;
	}
}
ImageFileAnimator.vcssl

That concludes the source code.

License

This VCSSL/Vnano code (files with the ".vcssl" or ".vnano" extensions) is released under the CC0 license, effectively placing it in the public domain. If any sample code in C, C++, or Java is included in this article, it is also released under the same terms. You are free to use, modify, or repurpose it as you wish.

* The distribution folder also includes the VCSSL runtime environment, so you can run the program immediately after downloading. The license for the runtime is included in the “License” folder.
(In short, it can be used freely for both commercial and non-commercial purposes, but the developers take no responsibility for any consequences arising from its use.) For details on the files and licenses included in the distribution folder, please refer to "ReadMe.txt".

* The Vnano runtime environment is also available as open-source, so you can embed it in other software if needed. For more information, see here.


Japanese English
[ Prev | Index | Next ]
Simple Tool for Viewing and Converting Between RGB Values and Color Codes

Display and Convert RGB Values and Color Codes on a GUI Tool
A Simple Tool for Making Specific Colors Transparent (Batch Processing Version)

Batch-Convert a Specific Color to Transparency in All PNG Files in a Folder
A Simple Tool for Making Specific Colors Transparent

Convert a Specific Color to Transparency in PNG Image Files
Simple Tool for Animating Sequential Images

A lightweight tool developed with VCSSL that allows you to play back sequential image files as an animation without converting them into a video file.
Vertex Array-Based Model Deformation Animation

How to Deform 3D Surface Models Using a Grid-Based Vertex Array
Creating a Model from a Vertex Array (Quadrangle Grid Mesh Format)

How to Create 3D Surface Models from a Grid-Based Vertex Array
Index
[ Prev | Index | Next ]
Simple Tool for Viewing and Converting Between RGB Values and Color Codes

Display and Convert RGB Values and Color Codes on a GUI Tool
A Simple Tool for Making Specific Colors Transparent (Batch Processing Version)

Batch-Convert a Specific Color to Transparency in All PNG Files in a Folder
A Simple Tool for Making Specific Colors Transparent

Convert a Specific Color to Transparency in PNG Image Files
Simple Tool for Animating Sequential Images

A lightweight tool developed with VCSSL that allows you to play back sequential image files as an animation without converting them into a video file.
Vertex Array-Based Model Deformation Animation

How to Deform 3D Surface Models Using a Grid-Based Vertex Array
Creating a Model from a Vertex Array (Quadrangle Grid Mesh Format)

How to Create 3D Surface Models from a Grid-Based Vertex Array
News From RINEARN
* VCSSL is developed by RINEARN.

English Documentation for Our Software and VCSSL Is Now Nearly Complete
2025-06-30 - We're happy to announce that the large-scale expansion of our English documentation with the support of AI — a project that began two years ago — has now reached its initial target milestone.

VCSSL 3.4.52 Released: Enhanced Integration with External Programs and More
2025-05-25 - This update introduces enhancements to the external program integration features (e.g., for running C-language executables). Several other improvements and fixes are also included. Details inside.

Released: Latest Version of VCSSL with Fixes for Behavioral Changes on Java 24
2025-04-22 - VCSSL 3.4.50 released with a fix for a subtle behavioral change in absolute path resolution on network drives, introduced in Java 24. Details inside.

Released the Latest Versions of RINEARN Graph and VCSSL - Now Supporting Customizable Tick Positions and Labels!
2024-11-24 - Starting with this update, a new "MANUAL" tick mode is now supported, allowing users to freely specify the positions and labels of ticks on the graph. We'll explain the details and how to use it.

Released Exevalator 2.2: Now Compatible with TypeScript and Usable in Web Browsers
2024-10-22 - The open-source expression evaluation library, Exevalator, has been updated to version 2.2. It now supports TypeScript and can be used for evaluating expressions directly in web browsers. Explains the details.

Behind the Scenes of Creating an Assistant AI (Part 1: Fundamental Knowledge)
2024-10-07 - The first part of a series on how to create an Assistant AI. In this article, we introduce the essential knowledge you need to grasp before building an Assistant AI. What exactly is an LLM-based AI? What is RAG? And more.

Launching an Assistant AI to Support Software Usage!
2024-09-20 - We've launched an Assistant AI that answers questions about how to use RINEARN software and helps with certain tasks. Anyone with a ChatGPT account can use it for free. We'll explain how to use it.

Software Updates: Command Expansion in RINEARN Graph, and English Support in VCSSL
2024-02-05 - We updated our apps. This updates include "Enhancing the Command-Line Features of RINEARN Graph" and "Adding English Support to VCSSL." Dives into each of them!