Fuse and Split Frames

Hi! :smiley:

Iโ€™d like to suggest adding to Aseprite the ability to fuse and split frames. I know they are 2 separated features, but as they are very related I thought it was a good idea to put them on the same post.

These features may become very handy when you are working on animating different layers (with different frame durations each) at the same time.


Fuse Frames:

  1. Select the frames that you want to fuse (Aseprite already calculates and shows the total time of all the selected frames).
  2. Right click on frames > choose โ€œFuse Framesโ€.
  3. If the image info of any the frames is different, a warning will appear so you know it, but you can continue anyway (Aseprite will use then the image info of the first selected frame).
  4. The selected frames will become only one frame, with the time duration resulting of adding all frame durations.

Mockup image:


Split Frame:

  1. You select a frame.
  2. Right click on frames > choose โ€œSplit Framesโ€.
  3. An emergent dialog ask โ€œHow many frames do you want to split the frame into?โ€ and you enter a number.
  4. The frame duration will be split evenly (for example, if the initial frame has 500 ms and you split it into 5 frames, at the end youโ€™d have 5 frames of 100 ms each).
2 Likes

Yeah, That would be cool!

Hi @JJHaggar, those are nice features. Actually they might be easily implemented with some scripts too :thinking:

hi, try this (it seems to work, but you know - always save before using it):

-- SPLIT FUSE SPLIT 0.02
-- b236 
-- 
-- *** SAVE BEFORE USING THIS SCRIPT! *** 
-- 
-- NOTE that fuse function is bidirectional: 
-- if you select frames from nr. 5 to nr. 3, 
-- script will fuse the range to nr. 3
-- 
-- if you select frames from nr. 3 to nr. 5, 
-- script will fuse the range to nr. 5 
-- 
-- so far scripts ignore the changes of activeFrame or frame.duration, 
-- so they can't be reused in this case 
-- 



local frm = app.activeFrame
local f = frm.frameNumber 
local d = frm.duration 
local new_d = 0 
local all = app.activeSprite.frames 
local rng = app.range.frames



local dlgWin = Dialog{ title = "*** SPLIT FUSE ***  " } 

-- set dialog window 
dlgWin
	:number{ 
		id = "numba", 
		text = "split to frames", 
		decimals = integer 
		-- default value should be 0, if not then click ok to crash 
	}
	
	:button{ 
		text = "SPLIT", 
		onclick = function()
			fSplit(dlgWin) 
		end 
	} 
	
	:button{ 
		text = "FUSE", 
		onclick = function()
			fFuse() 
		end 
	}
	
-- show dialog window 
dlgWin:show{ wait = false } 



function fSplit(dlgWin) 
	
	-- wrap function in transaction, 
	-- so only one history step is generated 
	app.transaction( function() 
	
		local split = tonumber(dlgWin.data.numba) 
		
		if split <= 1 then 
			-- dear user: do not try to be funny 
			split = 2 
		end 
		
		for i = 1, split-1, 1 do 
			frm.duration = d/split 
			app.command.NewFrame() 
		end 
	
	end)
	
	-- close dialog	window 
	dlgWin:close() 
end



function fFuse() 
	
	-- wrap function in transaction, 
	-- so only one history step is generated 
	app.transaction( function() 
	
		for i = 1, #rng, 1 do 
			new_d = new_d + rng[i].duration
		end 

		local ff = rng[#rng].frameNumber 
		
		if f == ff then 
			rng[#rng].duration = new_d 
			for i = 1, #rng-1, 1 do 
				app.command.GotoPreviousFrame() 
				app.command.RemoveFrame()
			end 
		elseif f < ff then 
			rng[1].duration = new_d 
			app.command.GotoNextFrame() 
			for i = 1, #rng-1, 1 do 
				app.command.RemoveFrame() 
			end 
			app.command.GotoPreviousFrame() 
		end 
	
	end) 
	
	-- close dialog	window 
	dlgWin:close() 
end 

oh, and one thing: fuse will NOT warn you about different images in selected frames, thatโ€™s too advanced. at least for now :]

EDIT: script is now undoable in single step (thanks to eishiya), plus iโ€™m adding quick fuse version without dialog window

-- QUICK FUSE 0.01
-- b236 
-- 
-- *** SAVE BEFORE USING THIS SCRIPT! *** 
-- 
-- this has same functionality as fuse in split-fuse script, 
-- but without a dialog window it can be used 
-- as a quick fuse of frames with assigned shortcut 
-- 
-- NOTE that fuse function is bidirectional: 
-- if you select frames from nr. 5 to nr. 3, 
-- script will fuse the range to nr. 3
-- 
-- if you select frames from nr. 3 to nr. 5, 
-- script will fuse the range to nr. 5 
-- 



local frm = app.activeFrame
local f = frm.frameNumber 
local d = frm.duration 
local new_d = 0 
local all = app.activeSprite.frames 
local rng = app.range.frames


function fFuse() 
	
	-- wrap function in transaction, 
	-- so only one history step is generated 
	app.transaction( function() 
	
		for i = 1, #rng, 1 do 
			new_d = new_d + rng[i].duration
		end 

		local ff = rng[#rng].frameNumber 
		
		if f == ff then 
			rng[#rng].duration = new_d 
			for i = 1, #rng-1, 1 do 
				app.command.GotoPreviousFrame() 
				app.command.RemoveFrame()
			end 
		elseif f < ff then 
			rng[1].duration = new_d 
			app.command.GotoNextFrame() 
			for i = 1, #rng-1, 1 do 
				app.command.RemoveFrame() 
			end 
			app.command.GotoPreviousFrame() 
		end 
	
	end) 

end 

fFuse()
1 Like