It is currently October 22nd, 2024, 4:25 pm

Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Tips and Tricks from the Rainmeter Community
User avatar
nek
Posts: 121
Joined: November 3rd, 2019, 12:00 am

Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by nek »

Easing functions Simulator with ActionTimer plugin for skin creators
Image
Wait (Wait time number in milliseconds) and Steps (Repeat count number) represent ActionTimer plugin ActionList option

ActionList1=Repeat ActionName, Wait, Steps

Code: Select all

[MeasureMoveRight]
Measure=Plugin
Plugin=ActionTimer
ActionList1=Repeat MoveRight, 15, 25
MoveRight=[!SetVariable OBJ_X "([#OBJ_X]+1)"][!SetOption SomeMeter X "[#OBJ_X]"][!UpdateMeter SomeMeter][!Redraw]



📦 EasingSimulator.rmskin (289 KB, GitHub.com)
SHA256 d7653d726deee1e7074f72bb5754e544c8fc7da6a8f38c0c51b49972f1354d8f

💡 Skin scaling: Menu > Settings > Skin scaling > 100% - 500%

This skin is for creators to find out the best easing function and values of Wait and Steps.

Example code: (skin included)
Image

Code: Select all


[Variables]

;; Scaling
$=1.00

SLIDE_X_MIN=0
SLIDE_X_MAX=240

;; These variables are used in the ActionTimer plugin. | https://docs.rainmeter.net/manual/plugins/actiontimer/#ActionList
;; Repeat (Action name), (Wait time number in milliseconds), (Repeat count number)
;; EASING_STEPS=(Repeat count number), EASING_STEPS_WAIT=(Wait time number in milliseconds)
EASING_STEPS=15
EASING_STEPS_WAIT=20

ACT_UPDATE_OBJECT=[!SetOption Object "X" "[#*OBJECT_OPTION_VALUE_NEW*]"][!UpdateMeter Object][!Redraw]

COLOR_OBJECT=FFFFFF
;;
;; # Temporary Variables
;;
;; EASING_COUNTER, OBJECT_OPTION_VALUE_START, OBJECT_OPTION_VALUE_END, OBJECT_OPTION_VALUE_NEW, OBJECT_WIDTH
;;

[Rainmeter]
Update=-1
;DefaultUpdateDivider=-1
AccurateText=1
MouseActionCursor=0
OnRefreshAction=[!Delay 800][!CommandMeasure pSlide "Execute 1"]

[sScript]
Measure=Script
ScriptFile=#@#Scripts\easings.lua
Disabled=1

;;
;;  function outQuint(x, s, e)
;;    @param   {number} x - counter/steps | range 0.0-1.0 | counter value start with 1, end with value equal to steps
;;    @param   {number} s - meter option start value
;;    @param   {number} e - meter option end value
;;    @returns {number}   - meter option new value
;;
[pSlide]
Measure=Plugin
Plugin=ActionTimer

ActionList1=StartUp1 | Wait 1 | Repeat Easing1,#EASING_STEPS_WAIT#,[#EASING_STEPS] | Wait 1200 | StartUp2 | Wait 1 | Repeat Easing2,#EASING_STEPS_WAIT#,[#EASING_STEPS] | Wait 1 | FinishUp

StartUp1=[!SetVariable OBJECT_OPTION_VALUE_START (#SLIDE_X_MAX#*#$#)][!SetVariable OBJECT_OPTION_VALUE_END (#SLIDE_X_MIN#*#$#)][!SetVariable EASING_COUNTER 0]
Easing1=[!SetVariable EASING_COUNTER ([#EASING_COUNTER]+1)][!SetVariable OBJECT_OPTION_VALUE_NEW ([&sScript:outQuint(([#EASING_COUNTER]*1/[#EASING_STEPS]),[#OBJECT_OPTION_VALUE_START],[#OBJECT_OPTION_VALUE_END])])]#ACT_UPDATE_OBJECT#

StartUp2=[!SetVariable OBJECT_OPTION_VALUE_START (#SLIDE_X_MIN#*#$#)][!SetVariable OBJECT_OPTION_VALUE_END (-[#OBJECT_WIDTH])][!SetVariable EASING_COUNTER 0]
Easing2=[!SetVariable EASING_COUNTER ([#EASING_COUNTER]+1)][!SetVariable OBJECT_OPTION_VALUE_NEW ([&sScript:inBack(([#EASING_COUNTER]*1/[#EASING_STEPS]),[#OBJECT_OPTION_VALUE_START],[#OBJECT_OPTION_VALUE_END])])]#ACT_UPDATE_OBJECT#

FinishUp=[!SetVariable OBJECT_OPTION_VALUE_NEW [#OBJECT_OPTION_VALUE_END]]#ACT_UPDATE_OBJECT#


[Container]
Meter=Image
W=(240*#$#)
Group=gBackground
SolidColor=FFFFFF

[Background]
Meter=Image
W=(240*#$#)
Container=Container
Group=gBackground
SolidColor=1F2937
LeftMouseUpAction=[!CommandMeasure pSlide "Stop 1"][!Delay 16][!CommandMeasure pSlide "Execute 1"]

[Object]
Meter=String
X=0R
Text=Click to start sliding
AntiAlias=1
Container=Container
FontColor=#COLOR_OBJECT#
FontFace=Segoe UI
FontSize=(18*#$#)
FontWeight=600
Padding=(8*#$#),0,(8*#$#),0

[Ninja]
Meter=String
Hidden=1
OnUpdateAction=[!SetOptionGroup gBackground H "[Object:H]"][!UpdateMeterGroup gBackground][!SetVariable OBJECT_WIDTH "[Object:W]"]



💡 [#EASING_COUNTER] is an another syntax of variable. 📗 Nesting Variables

Code: Select all

[Variables]
COUNTER=0

[Meter]
...
LeftMouseUpAction=[!SetVariable COUNTER "([#COUNTER]+1)"][!Log "standard=#COUNTER#, nested=[#COUNTER]"]
Output standard=0, nested=1



@Resources\Scripts\easings.lua

Code: Select all


local pi, pow, sqrt, sin, cos = math.pi, math.pow, math.sqrt, math.sin, math.cos

-----------------------------------------------------------------------------
-- Easing math functions
--
-- @see  https://easings.net
-- @see  https://github.com/ai/easings.net
--
-- License:  GPL-3.0  https://raw.githubusercontent.com/ai/easings.net/master/LICENSE
-----------------------------------------------------------------------------

local c1, c2, c3, c4, c5 = 1.70158, 2.5949095, 2.70158, (2 * pi) / 3, (2 * pi) / 4.5
local n1, d1 = 7.5625, 2.75

local function _OutBounce(x)
	if x < 1 / d1 then
		return n1 * x * x
	elseif x < 2 / d1 then
		return n1 * (x - 1.5 / d1) * (x - 1.5 / d1) + 0.75
	elseif x < 2.5 / d1 then
		return n1 * (x - 2.25 / d1) * (x - 2.25 / d1) + 0.9375;
	else
		return n1 * (x - 2.625 / d1) * (x - 2.625 / d1) + 0.984375;
	end
end

-- slow In

local function easeInSine(x)
	return 1 - cos((x * pi) / 2)
end

local function easeInQuad(x)
	return x * x
end

local function easeInCubic(x)
	return x * x * x
end

local function easeInQuart(x)
	return x * x * x * x
end

local function easeInQuint(x)
	return x * x * x * x * x
end

local function easeInExpo(x)
	return 0==x and 0 or pow(2, 10 * x - 10)
end

local function easeInCirc(x)
	return 1 - sqrt(1 - pow(x, 2))
end

local function easeInBack(x)
	return c3 * x * x * x - c1 * x * x
end

local function easeInElastic(x)
	if 0==x then
		return 0
	elseif 1==x then
		return 1
	else
		return -pow(2, 10 * x - 10) * sin((x * 10 - 10.75) * c4)
	end
end

local function easeInBounce(x)
	return 1 - _OutBounce(1 - x)
end

-- slow Out

local function easeOutSine(x)
	return sin((x * pi) / 2)
end

local function easeOutQuad(x)
	return 1 - ( 1 - x) * (1 - x)
end

local function easeOutCubic(x)
	return 1 - pow(1 - x, 3)
end

local function easeOutQuart(x)
	return 1 - pow(1 - x, 4)
end

local function easeOutQuint(x)
	return 1 - pow(1 - x, 5)
end

local function easeOutExpo(x)
	return 1==x and 1 or 1 - pow(2, -10 * x)
end

local function easeOutCirc(x)
	return sqrt(1 - pow(x - 1, 2))
end

local function easeOutBack(x)
	return 1 + c3 * pow(x - 1, 3) + c1 * pow(x - 1, 2)
end

local function easeOutElastic(x)
	if 0==x then
		return 0
	elseif 1==x then
		return 1
	else
		return pow(2, -10 * x) * sin((x * 10 - 0.75) * c4) + 1
	end
end

local function easeOutBounce(x)
	return _OutBounce(x)
end

-- slow InOut

local function easeInOutSine(x)
	return -(cos(pi * x) - 1) / 2
end

local function easeInOutQuad(x)
	return x < 0.5 and 2 * x * x or 1 - pow(-2 * x + 2, 2) / 2
end

local function easeInOutCubic(x)
	return x < 0.5 and 4 * x * x * x or 1 - pow(-2 * x + 2, 3) / 2
end

local function easeInOutQuart(x)
	return x < 0.5 and 8 * x * x * x * x or 1 - pow(-2 * x + 2, 4) /2
end

local function easeInOutQuint(x)
	return x < 0.5 and 16 * x * x * x * x * x or 1 - pow(-2 * x + 2, 5) / 2
end

local function easeInOutExpo(x)
	if 0==x then
		return 0
	elseif 1==x then
		return 1
	else
		return x < 0.5 and pow(2, 20 * x - 10) / 2 or (2 - pow(2, -20 * x + 10)) / 2
	end
end

local function easeInOutCirc(x)
	return x < 0.5 and (1 - sqrt(1 - pow(2 * x, 2))) / 2 or (sqrt(1 - pow(-2 * x + 2, 2)) + 1) / 2
end

local function easeInOutBack(x)
	return x < 0.5 and (pow(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2 or (pow(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2
end

local function easeInOutElastic(x)
	if 0==x then
		return 0
	elseif 1==x then
		return 1
	elseif x < 0.5 then
		return -(pow(2, 20 * x - 10) * sin((20 * x - 11.125) * c5)) / 2
	else
		return (pow(2, -20 * x + 10) * sin((20 * x - 11.125) * c5)) / 2 + 1
	end
end

local function easeInOutBounce(x)
	return x < 0.5 and (1 - _OutBounce(1 - 2 * x)) / 2 or (1 + _OutBounce(2 * x - 1)) / 2
end


-----------------------------------------------------------------------------
-- Easing functions for Rainmeter skin
--
-- @param   {number}  x  -  counter/steps | range 0.0-1.0 | counter value start with 1, end with value equal to steps
-- @param   {number}  s  -  meter option start value
-- @param   {number}  e  -  meter option end value
-- @return  {number}     -  meter option new value
-----------------------------------------------------------------------------

function Linear(x, s, e)
	return s + (e-s) * x
end

-- slow in

function inSine(x, s, e)
	return s + (e-s) * easeInSine(x)
end

function inQuad(x, s, e)
	return s + (e-s) * easeInQuad(x)
end

function inCubic(x, s, e)
	return s + (e-s) * easeInCubic(x)
end

function inQuart(x, s, e)
	return s + (e-s) * easeInQuart(x)
end

function inQuint(x, s, e)
	return s + (e-s) * easeInQuint(x)
end

function inExpo(x, s, e)
	return s + (e-s) * easeInExpo(x)
end

function inCirc(x, s, e)
	return s + (e-s) * easeInCirc(x)
end

function inBack(x, s, e)
	return s + (e-s) * easeInBack(x)
end

function inElastic(x, s, e)
	return s + (e-s) * easeInElastic(x)
end

function inBounce(x, s, e)
	return s + (e-s) * easeInBounce(x)
end

-- slow out

function outSine(x, s, e)
	return s + (e-s) * easeOutSine(x)
end

function outQuad(x, s, e)
	return s + (e-s) * easeOutQuad(x)
end

function outCubic(x, s, e)
	return s + (e-s) * easeOutCubic(x)
end

function outQuart(x, s, e)
	return s + (e-s) * easeOutQuart(x)
end

function outQuint(x, s, e)
	return s + (e-s) * easeOutQuint(x)
end

function outExpo(x, s, e)
	return s + (e-s) * easeOutExpo(x)
end

function outCirc(x, s, e)
	return s + (e-s) * easeOutCirc(x)
end

function outBack(x, s, e)
	return s + (e-s) * easeOutBack(x)
end

function outElastic(x, s, e)
	return s + (e-s) * easeOutElastic(x)
end

function outBounce(x, s, e)
	return s + (e-s) * easeOutBounce(x)
end

-- slow inout

function inoutSine(x, s, e)
	return s + (e-s) * easeInOutSine(x)
end

function inoutQuad(x, s, e)
	return s + (e-s) * easeInOutQuad(x)
end

function inoutCubic(x, s, e)
	return s + (e-s) * easeInOutCubic(x)
end

function inoutQuart(x, s, e)
	return s + (e-s) * easeInOutQuart(x)
end

function inoutQuint(x, s, e)
	return s + (e-s) * easeInOutQuint(x)
end

function inoutExpo(x, s, e)
	return s + (e-s) * easeInOutExpo(x)
end

function inoutCirc(x, s, e)
	return s + (e-s) * easeInOutCirc(x)
end

function inoutBack(x, s, e)
	return s + (e-s) * easeInOutBack(x)
end

function inoutElastic(x, s, e)
	return s + (e-s) * easeInOutElastic(x)
end

function inoutBounce(x, s, e)
	return s + (e-s) * easeInOutBounce(x)
end

Note: There are some gaps to consider. `(#SLIDE_X_MAX#*#$#)` might be `96.25`, 30 steps: `1/30`=`0.03333`


📗 ActionTimer, Inline Lua
> The skin is based on DanielPodo's code
> Learning the Basics(recommended!) by DanielPodo << Thank you!
> Easing math functions are from https://easings.net


nek wrote: OneTicker is also a Rainmeter skin using these easing functions.
oneticker.preview.gif
You do not have the required permissions to view the files attached to this post.
RicardoTM
Posts: 404
Joined: December 28th, 2022, 9:30 pm
Location: México

Re: Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by RicardoTM »

Hey Nek, first of all thank you for this, it's really useful.

I was wondering if you could guide me on using it to change a value between 0 and 1 multiple times. I tried but the number just will take time to get from 0 to 1 and viceversa but I can't make it to do what I want.

To explain, I want the number to start on 0 and end on 1 and then start on 1 and end on 0, but it should go: 0-1-0-1-0-1-0-1 and then 1-0-1-0-1-0-1-0 (using the easings of course), like mimicking an old light bulb that flickers before turning on.

Here's what I have:

Code: Select all

[Turner]
measure=Plugin
Plugin=ActionTimer
ActionList1=SetUp  | Repeat TurnON, 24, 12 
SetUp=[!SetVariable TurnerState 12]
TurnON=[!SetVariable TurnerState "([#TurnerState]-1)"][!SetVariable ButtonState (round([&C:inElastic(([#TurnerState]/12),(1),(0))]))][!Update][!Redraw]
ActionList2=SetUp2  | Repeat TurnOff, 24, 12 
SetUp2=[!SetVariable TurnerState 0]
TurnOff=[!SetVariable TurnerState "([#TurnerState]+1)"][!SetVariable ButtonState (round([&C:inElastic(([#TurnerState]/12),(1),(0))]))][!Update][!Redraw]
UpdateDivider=-1
I managed to do something close to what I want by not using the easings lol, but I want something more organic, this does more or less what I want:

Code: Select all

[Turner]
measure=Plugin
Plugin=ActionTimer
ActionList1=SetUp  | Repeat TurnON, 48, 11 
SetUp=[!SetVariable TurnerState 1]
TurnON=[!SetVariable ButtonState "(1-[#ButtonState])"][!Update][!Redraw]
ActionList2=SetUp2  |Repeat TurnOff, 48, 11 
SetUp2=[!SetVariable TurnerState 0]
TurnOff=[!SetVariable ButtonState "(1-[#ButtonState])"][!Update][!Redraw]
UpdateDivider=-1
Thank you in advance.
User avatar
Yincognito
Rainmeter Sage
Posts: 8532
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by Yincognito »

RicardoTM wrote: October 19th, 2024, 7:33 am To explain, I want the number to start on 0 and end on 1 and then start on 1 and end on 0, but it should go: 0-1-0-1-0-1-0-1 and then 1-0-1-0-1-0-1-0 (using the easings of course), like mimicking an old light bulb.
In one single action (0-1-0-1-0-1-0-1-1-0-1-0-1-0-1-0) or in two separate actions (0-1-0-1-0-1-0-1 and 1-0-1-0-1-0-1-0)?

Anyway, here's the Lua code for the separate actions version, since they could be executed one after another in the Rainmeter code (one could get rid of the 1st function and just multiply with (x % 2) in the 2nd function, but to follow the script structure I put this in two functions):

Code: Select all

local function easeOnOffBulb(x)
	return x % 2
end

-- ...

function onoffBulb(x, s, e)
	return s + (e-s) * easeOnOffBulb(x)
end
Take into account that x above is NOT the (counter / steps) value, but the counter value alone. This is because identifying whether the former value is the "even" or "odd" function execution is not possible since the division elements are both lost if passing only the duvision result to the function, while the same is trivial for the latter value.

Also, take into account that, based on your description, you need to have an "odd" number of steps (or counter maximum) so that with the "start up" aka the 0-th step they make up an "even" number of function executions (e.g. 0-1-0 will start and end at the undesired same value, but 0-1-0-1 will start and end at desired different values).

By the way, as a bonus, this will also work for other non zero outputs, e.g. 0-7-0-7 or 7-0-7-0, for conveniency. Obviously, you control the start and end value via the s and e arguments, so onoffBulb(0...3, 0, 5) will give 0-5-0-5, while onoffBulb(0...3, 5, 0) will give 5-0-5-0.

Hopefully this will fully work as I described, since it's untested and written from my phone. ;-)

P.S. I think the 2nd function for one single action will have to take the steps value as its y parameter too, so something like:

Code: Select all

function onoffBulb(x, y, s, e)
	return s + (e-s) * (x / y < 0.5 and easeOnOffBulb(x) or 1 - easeOnOffBulb(x))
end
should do. Not really "easing" functions, more like "switching" ones, but hey, you wanted them integrated along with the former, so... :confused:
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
RicardoTM
Posts: 404
Joined: December 28th, 2022, 9:30 pm
Location: México

Re: Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by RicardoTM »

Yincognito wrote: October 19th, 2024, 12:45 pm
Hey yin, thank you. Your equations work, although not how I envisioned. Although they do the flickering animation, it is still "too perfect". But I think I wasn't really specific, I envision something more "organic" like what the bounce and elastic animations do. Those functions start/end slow and end/start fast, that's what I mean with an easing animation, not that I wanted a function that's only part of the "easings script" :lol:

However, I truncated the formula and used ((1-counter)/steps) ((Trunc(1-[&C:outElastic(([#Counter])/Steps,(1),(0))])) and the original easings started "working" but not as I expected either lol. The outElastic being the only one that does "more or less" what I want.
ezgif.com-video-to-gif-converter.gif
Your function is actually closer, although it's still too linear.
ezgif.com-video-to-gif-converter (2).gif
(The lack of frames on the gifts will make it look different, but it flickers more irl)

I'd like something more "random" like it could go: 0-1-0-0-1-0-1-1-0-0-1-0-1 or something like that (I know I wasn't specific at all on my eralier post lol, I thought "mimicking an old light bulb that flickers before turning on" was :lol:), the more random the better.

edit:

Ok, after some invesrtigation and testing, I came up with:

Code: Select all

local function easeOnOffBulb(x, s, e)
    local flickerChance = math.random()
    if flickerChance < 0.3 then
        return s
    elseif flickerChance < 0.6 then
        return e
    else
        return e
    end
end

----------

function onoffBulb(x, s, e)
    return easeOnOffBulb(x, s, e)
end

That flickers better, although it makes it difficult to make sure it will always turn on or off :lol: So not quite there yet haha, it looks nice tho, I even like it as a "fidget toy" :rofl:.
ezgif.com-video-to-gif-converter (1).gif
You do not have the required permissions to view the files attached to this post.
User avatar
Yincognito
Rainmeter Sage
Posts: 8532
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by Yincognito »

RicardoTM wrote: October 19th, 2024, 11:13 pm Hey yin, thank you. Your equations work, although not how I envisioned. Although they do the flickering animation, it is still "too perfect". But I think I wasn't really specific, I envision something more "organic" like what the bounce and elastic animations do. Those functions start/end slow and end/start fast, that's what I mean with an easing animation, not that I wanted a function that's only part of the "easings script" :lol:
I get what you mean - which is why I was surprised that you mentioned that example output here. Here's a better approximation, made in TechCalc from my phone:
Screenshot_20241020_184533_TechCalc.jpg
It's not random, but it's an easing style function (in the formula, x would be count / steps aka the standard x argument of nek's functions, and 16 would be the steps value). If you output s when this function is negative or zero and e when the function is positive, you might get an easing from of blinking that's less frequent near start, becoming more frequent between start and end, and becoming less frequent near end. Not sure if the intervals between blinks are large enough to be noticeable with the naked eye for a larger number of steps, but it's a nice sinusoidal anyway. Or, you can explore the random variant you mentioned, try new functions, etc. ;-)
You do not have the required permissions to view the files attached to this post.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
RicardoTM
Posts: 404
Joined: December 28th, 2022, 9:30 pm
Location: México

Re: Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by RicardoTM »

I decided to keep the function I made as it was, I think it's great the way it is, I decided to rename it to inoutFlicker().

Code: Select all

local function easeInOutFlicker(x, s, e)
    local flickerChance = math.random()
    if flickerChance < 0.3 then
        return s  
    elseif flickerChance < 0.6 then
        return e  
    else
        return e  
    end
end
----
----------------------------------------\\
--Returns s or e randomly.
----
function inoutFlicker(x, s, e)
    return easeInOutFlicker(x, s, e)
end
Simple conditionals can be used to make it always return 1 or 0 (or any number) when the counter ends:

Code: Select all

[OnOff]
Disabled=1
measure=Plugin
Plugin=ActionTimer
ActionList1=SetUp  | Repeat TurnON, [#fps], [#steps] | Finish
SetUp=[!SetVariable TurnerState "([#State] = 1 ? 0 : [#Steps])"]
TurnON=[!SetVariable TurnerState "([#TurnerState]+1)"][!SetVariable ButtonState "([#TurnerState] >= ([#Steps]-1) ? 1 : [&C:inoutFlicker([#TurnerState],0,1)])"][!Update]
ActionList2=SetUp | Repeat TurnOff, [#fps], [#steps]  | Finish
TurnOff=[!SetVariable TurnerState "([#TurnerState]-1)"][!SetVariable ButtonState "([#TurnerState] <= 0 ? 0 : [&C:inoutFlicker([#TurnerState],0,1)])"][!Update]
Finish=[!SetVariable State "([#ButtonState] = 0 ? 1 : 2)"][!Update]
UpdateDivider=-1
It looks pretty nice inmo
ezgif.com-video-to-gif-converter (5).gif
You do not have the required permissions to view the files attached to this post.
User avatar
Yincognito
Rainmeter Sage
Posts: 8532
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: Easing functions Simulator with ActionTimer plugin - Animations, Transitions

Post by Yincognito »

RicardoTM wrote: Today, 11:42 am I decided to keep the function I made as it was, I think it's great the way it is, I decided to rename it to inoutFlicker().
[...]
Simple conditionals can be used to make it always return 1 or 0 (or any number) when the counter ends:
[...]
It looks pretty nice inmo
It sure does - good idea with conditionals! :thumbup:
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth