Update to the latest version of OSGL here!
About
What is OSGL?
OSGL (Open-Source Graphical Library) is a graphical library designed to offer developers a straightforward, fast, and efficient way to read and write pixels to EditableImages.
Originally created as an alternative to CanvasDraw, a graphics-library specifically built for Roblox, OSGL focuses exclusively on providing a robust framework for working with EditableImages.
Currently in beta, OSGL is continually evolving, with many features coming soon. It’s user-friendly and specifically designed to be as fast as possible. Whether you’re building pixel art, animations, or unique visual effects, OSGL will allow you to get what you need, done. If you’re among the users who can use OSGL in live games, we’d love to see what you create!
OSGL is currently the most performant public EditableImage library on the platform.
So, what can OSGL do?
In OSGL, a “Window” is essentially an EditableImage
that allows you to draw whatever you want. You can easily create shapes, draw pixels, or even load textures directly from your PC in various file formats. This flexibility gives you the freedom to do absolutely anything! OSGL also comes with its own error handling, sometimes catching and managing common (and annoying) EditableImage errors! (Buffer out of bounds, I’m talking to you.)
OSGL provides users with a “Window”, also known as an EditableImage, that allows for drawing a variety of elements including shapes, textures, and text. Key features of OSGL include:
This library is a resource for developers looking to create pixel-based 2D or 3D games, as well as for projects that require efficient storage and manipulation of Pixel Data (for example, a drawing game!)
Examples
OSGL v1.2b, v1.3b v1.4b currently have no examples.
OSGL v1.1b Examples
144P Shrek, sampled at 15FPS:
Minecraft Wireframe 3D Renderer (60FPS):
Live shading and rotating render:
Quick tutorial
This documentation assumes a basic understanding of
Luau
. For those new to the language, numerous resources are available for learning.
You can learn more on the Docs.
The following tutorial will show you how to draw a circle to the screen.
Setting up
If you haven’t done so already, download the latest version of OSGL from either the Github releases or from the Roblox Marketplace. Once downloaded, insert it into Studio in a suitible place (such as ReplicatedStorage/Packages
)
Create an ImageLabel
in StarterGui
, with its BackgroundTransparency
set to 0. This ImageLabel
will act as your primary canvas for rendering graphics.
Lower resolutions cause blurred images! If you’re rendering at a low resolution, or just want a pixelated look, set the
ResampleMode
property of yourImageLabel
toPixelated
!
Additionally, create a LocalScript
in your desired location (e.g., StarterPlayer/StarterPlayerScripts
). This script will create our window and manage the rendering process.
Creating a window
In OSGL, a “window” is actually just a fancy name for an EditableImage
. All that OSGL does, is wrap this EditableImage
in an easy-to-use API for you; with a lot of handy features.
Before we can actually draw on our window, we need to create one. OSGL is split into sub-modules that each serve a different purpose (e.g, drawing on a window, creating a window, etc.). In this case, we want the Window
class which allows us to create our window.
local OSGL = require(ReplicatedStorage.Packages.OSGL)
local Window = OSGL.Window
There are four functions available for creating our window: Window.from
, Window.new
, Window.fromAssetId
, and Window.fromBuffer
. According to the API:
Window.from
: Creates an OSGL window from an existing EditableImage.
Window.new
: Creates an OSGL window by initializing a new EditableImage instance at the specified location.
Window.fromAssetId
: Given an assetId, creates a Window.
Window.fromBuffer
: Given a buffer, creates a Window.
Since we don’t have an existing EditableImage
and do not wish to use an assetId, nor a buffer, we’ll use Window.new
to create our window directly on the designated ImageLabel
:
local OSGL = require(ReplicatedStorage.Packages.OSGL)
local Window = OSGL.Window
local windowUi = -- *reference to windowUi, our `ImageLabel`*
-- Create our window, 500x500
local myWindow = Window.new(windowUi, { sizeX = 500, sizeY = 500 })
The example above creates an OSGL window, with a size of 500x500, under windowUi
. You can find more details about this function in the API.
And that’s it! We have our OSGL window ready and setup for rendering!
Rendering to our window
Now that we have our window, let’s make this code a bit more interesting:
local OSGL = require(ReplicatedStorage.Packages.OSGL)
local Window = OSGL.Window
local color = OSGL.color
local windowUi -- reference to windowUi, our `ImageLabel`
-- Create our window, 500x500
local myWindow = Window.new(windowUi, { sizeX = 500, sizeY = 500 })
myWindow.targetFPS = 270
myWindow
:Clear(color.BLACK)
:Render()
In summary, the code above creates a window with a size of 500x500 pixels, setting the target FPS to 270. It then clears the screen using the BLACK
color (0, 0, 0, 255). The Clear
method clears the window’s buffer with the specified color, and the Render
method displays the updated buffer on the screen.
It’s important to note that the method calls do not need to be chained. You can achieve the same effect with separate statements, as shown below:
myWindow:Clear(color.BLACK)
myWindow:Render()
It is at this point where we can render our circle.
We can utilize the draw
sub-module to render directly onto the buffer. All drawing functions require a Window
or Texture
(known as a DrawableObject
) to specify where to draw. For example, to draw a pixel, you would use the appropriate draw function provided by OSGL:
myWindow:Clear(color.BLACK)
-- It isn't necessary to clear the screen. If you want to keep the contents
-- of the previous frame, you can!
-- Draw a red pixel on `myWindow`, at 0, 0
draw.pixel(myWindow, 0, 0, color.RED)
myWindow:Render()
In this example, each operation within the loop is presented as separate statements. However, these statements can be combined into a single statement using method chaining, as shown below:
myWindow
:Clear(color.BLACK)
:Draw() -- Open a `DrawingContext`
:Pixel(0, 0, color.RED) -- `myWindow` is automatically passed as the first argument
:StopDrawing()
:Render()
Almost all methods in Window
return the Window
itself, however if you want to draw in the same statement, you can use the Draw
method, which will allow you to use all of the drawing functions. When you want to get the Window
object again, you can call StopDrawing
and the Window
object will be passed back.
We want to create a circle, so we can use the draw.circle
function to make our circle:
myWindow
:Clear(color.BLACK)
:Draw()
:Circle(250, 250, 50, color.RED)
:StopDrawing()
:Render()
This code will draw a red circle at (250, 250), with a radius of 50:
Perfect! You have rendered your first circle with OSGL! The docs contain all the information you need to know, so It’s recommended that you go read them!
Full code
local OSGL = require(ReplicatedStorage.Packages.OSGL)
local Window = OSGL.Window
local color = OSGL.color
local windowUi – reference to windowUi, our ImageLabel
– Create our window, 500x500
local myWindow = Window.new(windowUi, { sizeX = 500, sizeY = 500 })
myWindow.targetFPS = 270
myWindow
:Clear(color.BLACK)
:Draw()
:Circle(250, 250, 50, color.RED)
:StopDrawing()
:Render()
Contribution
OSGL is an open-source project, and we welcome your contributions! You’re encouraged to edit the source code and share your ideas. Feel free to participate via GitHub, Discord, or even on the DevForum. Your involvement is greatly appreciated!
Credits
While you do not need to credit me for using OSGL, acknowledging the original creator is always appreciated but entirely optional. You are free to modify the source code as you wish, but please refrain from reuploading or claiming the asset as your own work.