aseprite / api Goto Github PK
View Code? Open in Web Editor NEWScripting API for Aseprite
Home Page: https://www.aseprite.org/api/
License: MIT License
Scripting API for Aseprite
Home Page: https://www.aseprite.org/api/
License: MIT License
fromFile
states that it takes a filename, although I am not sure on what its supposed to take, is it a string with the pallete's name or is it a string of the path to the pallete?
Hello,
I'd like to suggest some extra validation for inputs given to Color
. Since hue is a periodic value, that would mean wrapping negative values. For other inputs, that would be clamping to the lower and upper bounds of the range.
local x = Color(-3, 255, 257)
local y = x.rgbaPixel
local z = Color(y)
print("RGB boundary checking.")
print(string.format("%08X", y)) -- FF01FFFD
print(string.format("%d, %d, %d", x.red, x.green, x.blue))
print(string.format("%d, %d, %d", z.red, z.green, z.blue))
-- The % operator is floor modulo in Lua.
local u = Color{ h = -18.0, s = 1.2, v = 1.0 }
local v = Color{ h = (-18.0 % 360.0), s = 1.0, v = 1.0 }
print("\nHue boundary checking.")
print(string.format("u hue: %d", u.hsvHue))
print(string.format("v hue: %d", v.hsvHue))
print(string.format("u sat: %d", u.hsvSaturation))
print(string.format("%d, %d, %d", u.red, u.green, u.blue))
print(string.format("%d, %d, %d", v.red, v.green, v.blue))
print(string.format("%08X", u.rgbaPixel)) -- FF00B4FF
print(string.format("%08X", v.rgbaPixel)) -- FF4C00FF
As it stands, there is overflow when a color is converted to an integer. It looks like there may be some boundary checking for other arguments given to HSV conversion, such as saturation.
I'm referring more to the public-facing color_class
, not to internal color
class methods: https://github.com/aseprite/aseprite/blob/6b2c296ef0c00a42d76d3f76ecf6efb50009a88a/src/app/script/color_class.cpp#L38 .
Thank you for considering this idea.
Best,
Jeremy
Dialog method onclose is not invoked if Aseprite is closed with dialogs open.
I discovered It when testing an extension with a script that saves dialog position using onclose method.
Iam working on exporter plugin for aseprite and currently one of main problems I have with it is lack of ability to open file picker dialog as well folder picker dialog (also with their "save as" variant not only pick file).
Would be nice to have something like "pickFileButton" in dialog
As far as I can tell, it is not currently possible to create a layer any other way other than by using Sprite:newLayer()
and there is no way to reorder layers from within scripts either.
A way to access the layers' index within the parent layer group would be very welcome.
Hi again,
This is a feature request.
For objects that can be constructed from file paths -- such as ColorSpaces, Sprites and Palettes -- I think it would be helpful to mention and to link to app.fs
, specifically this section. This gives readers a heads up for how they can get greater flexibility over error handling, such as when a file path is invalid. I was messing around pcall and xpcall with inconsistent results before remembering app.fs
. I'm still using xpcall
for palettes loaded from presets (this is in Aseprite v. 1.3beta-6).
Alternatively, a more dramatic revision would be to remove constructors that accept file paths. Loading functions can then be shifted to app.fs, where it is clearer that an error may be raised, nil
may be returned and more functionality for error handling can be provided.
Thank you for considering.
Best,
Jeremy
The following code doesn't seem to select anything, although similar calls work fine for drawing tools
app.preferences.selection.mode = 0 -- SelectionMode::NORMAL according to data/pref.xml
app.useTool{ tool="magic_wand", points={Point(10,10)} }
app.useTool{ tool="rectangular_marquee", points={Point(10,10), Point(20,20)} }
WAIDW?
It would be useful to expose the file selecting dialog for getting paths from the user as an alternative to giving the path as a a string input via Dialog.entry.
Suggested Features:
Hello,
I observed this in Aseprite version 1.3-beta5.
I found this out because I'm working on a custom new sprite dialog which lets the user set their own color profile. But I believe it would impact any dialog with a color widget or color shades widget that could be opened (intentionally or not) independent from an activeSprite
.
To Reproduce:
The color picker will display only grayscale colors. The rules for when or if the color picker is updated if I, say, close the gray scale image and open a new RGB image isn't clear.
Because script dialogs can be opened independently of sprites, and because dialogs have the capacity to create new sprites, the behaviour I would prefer is that the dialog's color picker and shades be independent of the current sprite's color mode as well.
Thanks for considering this.
Jeremy
Steps to reproduce with Aseprite v1.2.18:
NxScale.lua
script to Aseprite.UR64N_N3.aseprite
.Issue:
For scaling a new image is created and the original one is replaced by It. Pixels that were previously transparent are now drawn on the image.
Workaround:
If you save the result and restart Aseprite transparent pixels will be drawn correctly.
The combobox of the dialog has a field called option
and one called options
. The option
field is the one that will be pre-selected. For that to work, it has to be one of the strings provided to options
. It would be more clear to name the field selected_option
or at least to indicate the correct usage in the documentation.
Currently, dstImg: drawImage (srcImg, position)
, draws the srcImg
at the position referred to the limits of dstImg
. If the input argument position
is outside the limits of dstImg
, srcImg
is not drawn in dstImg
(I think this would be more useful if dstImg is enlarged according to the input arguments: srcImg
and position
).
Also, transparent pixels override opaque colors (I think this would be more intuitive to do an alpha composition, another option is to include an input arg flag as composition
selection).
Low priority.
Despite being mentioned in the API documentation of Tag
, the getter Tag.color
is not exposed, resulting in an error when trying to call it.
Suggestion: Either remove entry from documentation to avoid further confusion or add Tag.color
to api
Aseprite version: v1.2.17
API version: 9
Adding a ui boolean paramater to the MaskByColor command.
It would be great to be able to run the MaskByColor command without having the dialog pop up.
I know many of the dialogs have this already but it seems this one is missing it.
Add the possibility to group widgets to modify all of them together with one Dialog:modify()
call.
Would it be possible to update the API documentation with the parameters for app.command.MoveCel?
Unfortunately it doesn't have any relevant information in gui.xml and decoding the source for it in cmd_move_cel.cpp and the timeline/context scripts was far beyond my skill and knowledge.
I tried quite a few combination of parameter names based on those pages, seeing if I'd hit the jackpot (srcLayer, srcFrame, toFrame, passing numbers, passing ranges, layer/frame objects, etc, etc.) seeing if I'd get a result, but nope. I scrubbed all Aseprite scripts and the examples seeing if there was a reference, but no luck either.
Reason I'm asking is that I'm writing a couple QoL scripts that involve moving cels around, tagging, etc. to automate how I get sprites for my game and the lack of API documentation regarding moving cels has made me do things in awkward manners: Currently, my code 1) copies the cels one by one, 2) deletes the original cels, 3) checks if they have to be relinked 4) relinks them. This isn't very efficient. If I could just pass a range or something, it would be a lot easier, but not so without a little more info.
Apologies if this is not the place to be asking.
It would be nice to be able to "Remap" the palette from scripts or make the button visible if the script modifies the palette.
At the moment the difficult part of this one is where/how to indicate the "start point of modifications". In the UI it's from the first modification of the user palette, on scripts it might be good to have a way to indicate the start of modifications (maybe the start of a transaction?)
From: https://community.aseprite.org/t/sort-swatches-by-usage-suggestion/1641/7?u=dacap
Currently the only way to load an external Image into an already existing sprite is to use app.open([imagepath]) and extract the image from the associated cel and insert it into the existing sprite, then closing the temporary sprite with app.command.CloseFile().
The only way to extract an individual image seems to be to create a new sprite, insert the needed image, and use Sprite.SaveAs([path]).
If it does not break the API specs, it could be useful to have some means of importing and exporting Images directly from the Image class.
The docs state that If position [the second argument] is a point, it will put the given image in the given position
with regard to Image:putImage(). I would expect the Point given to be relative to the Sprite, (0, 0)
being the top left. I've gotten different results with this, however.
On one sprite, it seemed that the position given would be relative to the top left of the image already existing in that cel. On a blank cel of the same sprite, it was relative to the top left of the Sprite which is what I would expect.
If I create a brand new sprite however, instead of moving the image, it actually puts the image in the very top left no matter what, and the point given actually clips the sprite.
To reproduce the clipping bug, create a new sprite of any size and draw anything. Then execute the attached Lua script and choose "Apply to new layer".
When trying to call:
local g = app.pixelColor.grayaG(color)
Where color is a result of a call to image:getPixel gives the error from the title.
I just spend some time to figure out that the line
if data.ok then
in the beginning of the documentation for the dialog class actually checks if the ok
field of data is true. I thought that this might be some data consistency check or whatnot and that I always have to check if the data is actually ok, before I can access it. This is a beginner mistake, yes. But since this example is probably one of the first things people new to scripting will try out (making a hello world popup), it may happen to other beginners as well.
Solution: just rename the ok
id to confirm
. This is also consistent with the other button that has the cancel
id and is (imo) not as easily mistaken with a mandatory data check.
Currently these are the only things possible with the current modify function
that's a little lackluster. A couple more things we can modify are
onclick
, onchange
, onrelease
functionsoptions
for comboboxand two more functions I feel are needed
dialog:delete()
which should delete the element with the specified iddialog:replace()
should delete the element with the given id and create a new element with a new id in the same placeFor batch-export scripts, it would be useful if Dialog:path() could be scripted to select a folder, rather than just a single file.
Trying my hand at writing a few batch scripts for a project and have a couple suggestions
Was writing a script for an operation that I do pretty frequently, swapping palettes for a color reduced one, the operation is:
Change the color mode of the sprite to rgb
Load the reduced color palette
Change the color mode of the sprite back to index
The closest thing to changing the color mode, is opening the "color mode changing dialog" through app.command.ChangePixelFormat. It'd be nice to have a quiet method that doesn't open up a color mode changing dialog, but applies your settings directly to the sprite.
I work with photoshop, and sometimes saving the files as png results in the following error when opening up the png file: libpng: iccp: known incorrect srgb profile.
Which is due to the color profile being set to Photoshop ICC profile.
Choosing to ignore the error message would help stop the problem of script pausing for batch operations.
Which brings me to being able to change the color profile directly without having to go through sprite properties dialog. (changing the color profile to 'none' allows the faulty "photoshop ICC profile" png to actually save)
As in Dialog:modify()
we should be able to specify these properties in the widget creation:
The code must be added here:
https://github.com/aseprite/aseprite/blob/68720424c06e34ccdf8087328d6930c22d8adc98/src/app/script/dialog_class.cpp#L297
Hi!
As of today (2018-11-04 version 1.2.10-beta2) the app.pixelColor.rgba functions doesn't work as expected. The returned value is reversed from red, green, blue, alpha to alpha, blue, green, red.
local yellow = pc.rgba(255, 255, 0, 255)
print("Yellow:")
print("pc.rgba(255, 255, 0) = " .. yellow) -- 4278255615 aka FF00FFFF aka some pink.
print("red: " .. pc.rgbaR(yellow))
print("green: " .. pc.rgbaG(yellow))
print("blue: " .. pc.rgbaB(yellow))
print("\n")
local real_yellow = pc.rgba(255, 0, 255, 255) -- in the ABGR order.
print("Real yellow:")
print("pc.rgba(255, 0, 255, 255) = " .. real_yellow) -- 4294902015 aka FFFF00FF aka yellow
print("red: " .. pc.rgbaR(real_yellow))
print("green: " .. pc.rgbaG(real_yellow))
print("blue: " .. pc.rgbaB(real_yellow))
Have a nice day!
Image:drawImage()
should use NORMAL blend mode and we should be able to change this blending mode.
Hi,
first of all, thank you for this api, I'm experimenting on LUA, I'm working on a script where I read pixels data on a given sprite and I wanted to save the pixels informations I need in a .txt file for my game
So I tried to use
local file = io.open(path.."test.txt", "w+")
file:write('test')
file:close()
After allowing the writing access
Am I missing something?
Exactly as the title says - the number of frames is correct, however, they start from index/key 2 instead of 1 that documentation suggests.
Hello,
I have a feature request:
Would it be possible for app.transaction
to accept an optional string
argument so the transaction could be named? When the user runs a script, then wants to undo, they can open Undo History and have a better idea of what steps the script has taken. I realize that the user can already select a transaction in Undo History to see what state that would put in the image in, but some state changes may be less noticeable than others. To limit abuse, the string could have a minimum and maximum number of characters... or the string
could follow a prefix. For example
app.transaction { name = "Foo", method = function() app.alert("Foo!") end }
could have the name "[Script] Foo" in the Undo History.
Thank you for considering!
Jeremy
Is there any reason to disallow the package system? I could probably get by with loadfile()
, but it would require me to hard code system specific paths into my scripts.
Essentially i would like to create exporter for my own engine with different file format. For that it would be really usefull if i would be able to work with sprite sheet.
My idea is something like this:
local ss = Sprite:createSpriteSheet(rows, columns) --< Maybe some description table with params you normally enter in export dialog instead of just row and column
--! SpriteSheet minimal api:
ss.width
ss.height
ss:SafeToFile("Myfile.png")
for i,sframe in ss.sheetFrames do
--! minimal sheet frame API:
sframe.posx
sframe.posy
sframe.width
sframe.height
sframe.spriteFrameNumber
end
This would be enough to be able to do custom exporter with all data necessary to recreate animation in external renderer (engine)
After doing a few tests it seems that with the new floating windows have made dialogs a bit broken.
When dialogs options (ie buttons / sliders etc. ) are shown or hidden the dialog does not resize up or down to fit the size of the newly shown or hidden options. It does look like internally the dialog sees that it needs to change sizes but the sizes are not reflected correctly to the dialog window that is rendering.
Trying to modify the dialogs bounds also seems to freeze the dialog making it unable to accept any input.
Here is my simple code that I'm using to test this. Let me know if maybe I'm doing something wrong even or if this might actually be a bug in the system?
Here is also a video of me doing the testing:
https://gyazo.com/daf7c1a2c3054dc3307d1b1fba43ff4b
You can also see what is happening here as well:
https://gyazo.com/c02bca0fb52e7b0441b5a696f07ab7b9
... but this is not reflected in dialog.md. It's a nifty little feature, let's tell people about it
This obviously shouldn't be good because Aseprite will react very strangely to having a negative size for the image's canvas, as shown in the gif.
Aseprite thankfully already doesn't allow this under normal usage, it'll resize the sprite to 1x1.
However by resizing from a lua script, you can get around the check.
Example:
sprite:resize(-32, -32)
Hi!
I am trying to create a script that can save an animation from aseprite to my own custom file format. I already have the python script that converts a aseprite file to my format and i am able to run that script from Lua. The only problem that i have is that i first need to save the animation as a aseprite file and then converting it and if that is going to work, then i need to be able to get the path to were the file was saved. Are there any way to use app.command.SaveFileAs and get the path it saved the file to? If not, can i send an argument to app.command.SaveFileAs which says where it should save it?
The app.apiVersion
is not a good way to check for API features when we have this branch of versions (e.g. v1.2 and v1.3). We think that we could add a new object to check features:
if app.features.hasTilemapLayers then
...
end
In case of a property that doesn't exist is used (e.g. app.features.nonExistentFeature
) it just return false (instead of a Lua error).
Defining a function and executing it via app.transaction() does not group all operations in the function as one modification to the sprite, but instead defines the "transaction" as its own undo step while keeping everything in the function separate.
function drawstuff() app.useTool{ tool="rectangle", brush=Brush(1), points={Point(40,10),Point(80,80)} } app.useTool{ tool="rectangle", brush=Brush(1), points={Point(90,30),Point(110,80)} } end
app.transaction(drawstuff)
I've been puttering around with making a bunch of scripts to help automate making graphics for my NES games, which has been working out really well. The biggest issue I've run into is that debugging the scripts is really tedious without a debugger, and lua's minimal amount of built in "to string" capabilities makes log based debugging tedious too.
So... a shameless plug for a project I've been working on for a few years:
https://github.com/slembcke/debugger.lua
Why you might want to consider integrating it:
dbg.call()
/dbg_call()
to provide a drop in replacements for pcall()
/lua_pcall()
that attach the debugger on an error.I had tried using it before, but the lack of require()
, and io.read()
seemed to make it a non-starter. Since debugger.lua has retargetable I/O by overriding it's read()
and write()
functions, it occurred to me today that I could just use UNIX FIFOs to connect the I/O to a terminal. Voila! So apparently the I/O issue is the only thing holding it back.
I'll probably try integrating it myself, but I dunno how far I'll be able to get...
I am looking at the docs for app.command.ExportSpriteSheet
:
https://github.com/aseprite/api/blob/master/api/command/ExportSpriteSheet.md
And I cannot find an option for Ignore Empty
from the Export Sprite Sheet options:
this is basically what it should look like... (this is the environment variables list in windows)
it's essentially a combobox but instead of a dropdown it has a fixed width (just a number) and height in terms of number of entries that should fit before getting a scrollbar.
any extra entries should give it a scrollbar and the entries should be selectable using the mouse and navigable using arrow keys
ideally double clicking an entry should call an onclick
function which is passed the double clicked string but it's ok if not possible since it can be replicated using a button
Hello! I have an animated tile map I am trying to automate by copying the frames from a tile merged cell by cell into a new file. Selection and new frames work all well but when I attempt to paste my selection, the application crashes.
Script in Question:
do
local spr = app.activeSprite
if not spr then return app.alert "No Active Sprite" end
local basePath = "PathFromRoot/To/Tiles/Directory"
app.transaction(
function()
local current = app.open(basePath .. "/WaterTiles.aseprite")
local standardLayer = app.activeLayer
local newSprite = Sprite{ fromFile=basePath .. "/Test.aseprite" }
local newSpriteLayer = newSprite.layers[1]
for i = 1,8 do
local frame = newSprite:newEmptyFrame()
app.activeSprite = current
app.activeLayer = standardLayer
app.activeFrame = i
current.selection:select(Rectangle(0, 0, 16, 16))
app.command.CopyMerged()
app.activeSprite = newSprite
app.activeLayer = newSpriteLayer
app.command.Paste()
current.selection:deselect()
end
end
)
end
OS:
macOS BigSur 11.1
Any help would be appreciated!
It would be great to be able to set and get the position of a current selection's pivot point.
This way via scripting we could set a pivot point from a saved value taken before hand.
This little guy here is what I'm referring to as the pivot point / rotation point.
Some functions requested by Goomboo in the Discord server:
plugin
object will have a plugin.preferences
property which will be a standard Lua table that will maintain the values between sessions:
function init(plugin)
plugin.preferences.something = ...
end
It would be nice to be able to debug plugins in Lua editor like for example Zero Brane Studio:
https://studio.zerobrane.com/doc-remote-debugging
This may require to either have lua as dll instead of static library inside exe or at least added luasocket multiplatform library into Aseprite exe so it is possible to start a debug session. Also require needs to be allowed to load moddebug extension
goal: use ellipse tool to generate a sort of spinning ring effect:
To achieve this, I need to be able to specify an angle somehow for the ellipse tool.
At present, there is no way to specify modifiers for any points in a useTool
call.
For my own education, I have tried to trace how this is achieved in a regular (non-script) workflow. Not sure how accurate it is:
Editor::onProcessMessage
is called, which callsEditor::updateToolLoopModifiersIndicators
which callsAppEditor::getPressedKeyAction
which callsKeyboardShortcuts::getCurrentActionModifiers
which checks to see if any relevant keys are pressed.Editor::updateToolLoopModifiersIndicators
also callsDrawingState::notifyToolLoopModifiersChange
, which callsToolLoopManager::notifyToolLoopModifiersChange
, which callsToolLoopManager::movement
with the same pointer (not c++ pointer, aseprite tools::Pointer
) as was last used. It callsmovement
method, which checks the tool loop modifiers and sets the angle (assuming it's a TwoPointsController
, which I guess is what is used for the ellipse tool?). ToolLoopManager::movement
also callsToolLoopManager::doLoopStep
which callsjoinStroke
on the tool loop's intertwine, which for the ellipse tool is IntertwineAsEllipses
(I guess?), and that callsdraw_rotated_ellipse
using the angle from the loop's controller.Something like that, anyway.
One approach would be:
TwoPointsController
's angle field, which is currently private, to the tool loop or tool loop manager.angle
argument in App_useTool
when the tool is an ellipse. If it is present, set the controller angle to that value. We'd have to be careful that the angle is not accidentally overwritten at some point, I'm not sure all the ways that can happen.This approach seems a bit blunt, and doesn't really support the idea that script writers should have a generic way to apply modifiers as necessary. Maybe a different title for this issue could be "useTool should support tool loop modifiers" but I don't know where I would even start to work on something like that.
This is the first time I've actually looked through aseprite's code base, apologies if I'm missing something obvious or completely off the mark.
Thoughts?
My apologies if I'm missing something, is there currently a way to scale/resize a selection or image or any kind of workaround for that? I understand we can resize the sprite but I need to manipulate the selection/image itself.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.