hey! this pack is absolutely awesome and i like it extremely much, thank you!!
tho one single on them doesn't seem to work for me - its Regicide. It doesn't give me any error, but the images stay static without warping. I tried to put it on a layeredimage sprite with .pngs in it, on a .jpg background, on the whole screen using camera statement, and it doesn't seem to do any effect. Is there maybe any requirements for it that i need to know?
i also noticed that VHS and noise shaders show in low fps, but when the text in say window is showing, the fps is boosting up for some reason. is there a way to fix this? (Edit: I figured out that the problem occurs only when nothing moves on the screen (i.e no transforms are applying, no text are currently being typed etc), it\s much like renpy capping the framerate when there's nothing to show. but can i fix this without the need of any kind of movement on the screen?)
Without looking at the script and assets in their entirety it's hard to say what's preventing regicide from working. You could try making a copy of the transform and adjusting the settings, though the defaults should be enough.
The frame rate issue, as you suggested is an engine quirk. That's Ren'Py's default behavior you're running into. If you add this to any transform you're actively using, Ren'Py will render at full FPS as long as that transform is in use. It's worth noting that the shaders were written with this in mind and most of the included shaders do not have any frame limiting in them. This isn't a problem for most of them, but any of the shaders that include noise effects might be excessively animated as a result, depending on the resultant frame rate.
Exception: MakeVisualNovels.PerlinWarp: Unknown shader variable line '//Commonly used variables in nearly all shaders.'. Only the form '{uniform,attribute,vertex} {type} {name} is allowed.
-- Full Traceback ------------------------------------------------------------
Full traceback:
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\bootstrap.py", line 277, in bootstrap
renpy.main.main()
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\main.py", line 558, in main
renpy.game.context().run(node)
File "game/scripts/shaders/MVNRSP1.rpy", line 1, in script
init python:
File "/home/tom/ab/renpy-build/tmp/install.linux-x86_64/lib/python3.9/site-packages/future/utils/__init__.py", line 441, in raise_
File "game/scripts/shaders/MVNRSP1.rpy", line 1, in script
init python:
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\ast.py", line 1131, in execute
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\gl2\gl2shadercache.py", line 48, in register_shader
ShaderPart(name, **kwargs)
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\gl2\gl2shadercache.py", line 117, in __init__
raise Exception("{}: Unknown shader variable line {!r}. Only the form '{{uniform,attribute,vertex}} {{type}} {{name}} is allowed.".format(self.name, l))
Exception: MakeVisualNovels.PerlinWarp: Unknown shader variable line '//Commonly used variables in nearly all shaders.'. Only the form '{uniform,attribute,vertex} {type} {name} is allowed.
From the looks of it, your version of RenPy doesn't seem to like comments inside of the shader variable declaration, which is pretty odd. I would recommend updating to the newest version of RenPy and seeing if the issue persists.
This is really cool!
I wonder if there is a way to combine two shaders at once (say, Regicide and Animated Aberration) without getting the variables (uv, usually) clash?
There's a few ways to combine them, though I can't say I've looked too deeply about how they all look together.
The first way would be to apply one of the shaders to a layer and another shader to the displayables themselves. In doing that you can sort of stack two shaders together. RenPy docs on Layers here: https://www.renpy.org/doc/html/displaying_images.html#layer
The other way would be to directly edit the shader code to produce both effects, which I wouldn't recommend unless you're comfortable with writing shaders.
Right. The layer + displayable combo works, thank you.
I don’t think you’d want to be too crazy with the combinations anyway, this is partly fuelled by sheer curiosity xD
I’m using this shader pack in my newest game, and it works smoothly on my laptop and on Renpy’s Android emulator.
However, when running it on my phone (Xiaomi POCO M5 running on Xiaomi HyperOS 1.0.5.0 and Android version 14 UP1A.231005.007), I keep getting this error.
ShaderError: 0.39:S0001: Type mismatch in arithmetic operation between vec2 and int
Upon close inspection, it seems that this is primarily caused by the Regicide shader.
Is there anything I can do to address this problem? (I am fairly comfortable with coding, but my knowledge of shader is limited to porting shadertoy examples to Ren’py)
I don't have the code right in front of me, but if I had to guess the error is likely coming from an instance where we're multiplying or dividing a full integer (eg.: 8) instead of a float/double (e.g 8.0) or vec2 (e.g, (8.0 , 8.0)) I can't recall any specific instance where I did that, but that's where I would start looking.
Normally I'd jump in to assist directly, but I'm presently drowning in event prep work for the Spooktober VN Jam and likely won't have time to do a full dive with you for at least a few weeks. Let me know what you find in a reply here and I'll do my best to offer suggestions during my down time.
Thank you for your pointer! It’s alright, I will not expect you to do so, and I’ll likely just put the Android version on the backburner if I can’t find a way to solve this. I’ll tell you what I find, but please don’t feel like there’s any pressure to reply!
(Also, Regicide slaps, and I’ve been enjoying the Animated Aberration quite a bit too)
You’re right on the money!
The u_scale and u_flipScale in the file MVNTemplates.rpy are integers, and changing them to floats solve the problem!
Thank you very much!
Hi! Thank you very much for your shaders, they've been very helpful.
For some reason SimulatedLighting looks pixelated on my sprite ( link ). I've done some digging and it seems like
vec4 color = texture2D(tex0, uv);
is the problem. If I just set the gl_FragColor to color (literally gl_FragColor = color; ) it still is pixelated, just without the shader effect (obviously).
I am not sure what is the problem, but my sprites have quite a large resolution (though, changing it from 2000x1000 to 1000x500 didn't really help), so maybe resolution is the problem??? Renpy sometimes works in strange ways when sprites are too big. Or maybe (probably) it's something else, I don't know.
Well, anyway, I've found a solution. the color variable is only used in calculating the final color, so I just replaced the final line in the fragment shader to this:
And it looks ok ( link ), though, there are no alpha channel in it, but it works for me I guess ¯\_(ツ)_/¯.
Just wanted to leave it here in case anyone else has any similar problems, thanks again.
UPD: Just found an even better way to fix it!
Just change the color definition to:
vec4 color = gl_FragColor;
and it seems to work! Suprisingly simple, I guess, renpy doesn't like texture2D function? Anyway, it should (haven't checked) even work with the alpha channel now. Good luck.
Weeeird. I wish I had a picture of your sprite without influence from the shader so I could get a better idea of how things are changing.
You clearly know this because since you knew setting the output(gl_FragColor) to what you sampled would effectively disable any shader effects, but for everyone else: texture2d() is a function that returns a pixel(the color) at a given coordinate (uv) from a supplied texture, or tex0 as it's called in RenPy.
vec4 color = texture2d(tex0,uv) in this case would be the pixel color information from the source texture/image.
Shaders would then typically operate on, or using, this information to eventually assign it to the output, gl_FragColor. So in testing:
vec4 color = texture2D(tex0, uv);
gl_FragColor = color;
and still came up with artifacts is odd. I had spoken to Fen (go check them out btw they're awesome) and I recall something about v_tex_coord needing to be set to a_tex_coord in the Vertex shader-- I might be misremembering the details but if you're still getting those weird artifacts on your outputs when setting the input to the output (almost) directly, then we can really only assume that either the source texture or the coordinates are the problem.
I don't have it right in front of me at the moment, but if you're still toying with it and are familiar with it, it might be worth adding
v_tex_coord = a_tex_coord;
into the vertex shader and trying again. I'm about 80% sure I'm using v_tex_coord as UV, which feels like the most likely culprit.
If you're able to try and confirm it, I can add a correction into the pack pretty quick to prevent anyone else from running into the problem. Otherwise I'll see if I can reproduce and fix it when I have time. I'm currently drowning in VN dev, several new packs, Spooktober Jam scouting and prep, and a half dozen IRL things so I don't know when exactly I'll get to it.
It's okay, don't rush it, I found a solution for me (mentioned in the edit above, setting color to gl_FragColor). Thanks for your response. Here is the sprite link, though, as it turned out it doesn't matter really.
I've made a sample project to show it off link. I did it here with a standart sprite from "The Question", which is 500x700, so resolution isn't the problem, I guess.
And sadly no, setting v_tex_coord to a_tex_coord doesn't help. Really, it seems like a problem with renpy? I will open an issue on github some days later if we will not figure out the cause.
I also thought that it maybe show like that only when redacting the game project, but no, it is the same when the game is build, so it is either a problem with the shader (somehow?), renpy or my gpu (probably not, but would be nice to know if it's the same on your pc, there's always a chance, it is AMD by the way).
Update: just asked my friend has an Nvidia 1060 and it looks okay on his pc, I have an RX 6600 and it looks blurry...
Amazing shaders! Is there a way to modify the time of, for example, the AnimatedAberration? I don't know much about shaders. I saw a u_time variable, and I tried many things but couldn't make it work.
Excelent job, thank you so much!
PD: I was able to do it using normal animation methods, using StillAberration! Thanks!
Yep! So nearly any property that is supplied by the transform can be animated using the animation command. Good job on figuring out a way forward on it!
Ironically, it's harder to animate AnimatedAberration than it is to animate the still version of it from the outside. AnimatedAberration takes u_time into consideration, which is a uniform property that is representative of ongoing time. If you were able to set u_time to a constant value, it would.. actually stop animating! The changing of u_time as supplied by RenPy and the shader's uptime is actually driving that one's particular animation.
You could still animate Animated Aberration from the outside, but you'd only be able to animate the other exposed properties, and it probably would be hard to fine tune the appearance because the animation is baked into the shader itself for that one.
It was smart to go to the still version of it, because now you have significantly more control over how it behaves from the outside using the animation commands in RenPy. What you're doing is changing the values supplied by the transform directly, rather than having the shader calculate the latest step there.
I'd love to see how you did it, and I'm sure some other folks would too if you'd like to share.
I'm still knee-deep in dev, but your VHS filter is really helping me sell this aspect ratio change in the middle of my current game. Thank you so much for making these and sharing them! I feel like they've taken me a layer deeper into understanding what Ren'Py can do.
Yep! You can apply the premade transforms to backgrounds, characters, or entire layers.
I have an update that will include an example of this, but in the mean time you can set the Mesh property to true on a layer(or a transform you make/edit) and apply it to an entire layer, which can include anything on the screen that you add to it.
The master layer is the one you'd want to apply a transform to most of the time, if you're doing screen wide shaders.
My game's lighting just got even more bisexual, thank you!
Also, a note for anyone using layeredimages: You'll probably want to add mesh True to the transform!
Compared to before (with manual airbrushing):
Does there happen to be a way to set the colors based on the state of another variable? My game keeps track of which floor you're currently on, and each floor has different lighting conditions. If it was possible to apply the "right" lighting automatically, this would be a huge game changer. :O
Wow! It's looking great! And yes, I've actually thought about making a mention to folks using layered sprites to use that since I've had a few people come back and ask how to sort it out.
As for using a variable to adjust the lighting, you could do it with a custom written transform that accepts a variable parameters instead of hard coded ones. I'll be working on another pack on stream this week, so I'll put some time into getting an example for you to play with on Tuesday!
← Return to RenPy shader pack
Comments
Log in with itch.io to leave a comment.
hey! this pack is absolutely awesome and i like it extremely much, thank you!!
tho one single on them doesn't seem to work for me - its Regicide. It doesn't give me any error, but the images stay static without warping.
I tried to put it on a layeredimage sprite with .pngs in it, on a .jpg background, on the whole screen using camera statement, and it doesn't seem to do any effect. Is there maybe any requirements for it that i need to know?
i also noticed that VHS and noise shaders show in low fps, but when the text in say window is showing, the fps is boosting up for some reason. is there a way to fix this? (Edit: I figured out that the problem occurs only when nothing moves on the screen (i.e no transforms are applying, no text are currently being typed etc), it\s much like renpy capping the framerate when there's nothing to show. but can i fix this without the need of any kind of movement on the screen?)
Without looking at the script and assets in their entirety it's hard to say what's preventing regicide from working. You could try making a copy of the transform and adjusting the settings, though the defaults should be enough.
The frame rate issue, as you suggested is an engine quirk. That's Ren'Py's default behavior you're running into. If you add this to any transform you're actively using, Ren'Py will render at full FPS as long as that transform is in use. It's worth noting that the shaders were written with this in mind and most of the included shaders do not have any frame limiting in them. This isn't a problem for most of them, but any of the shaders that include noise effects might be excessively animated as a result, depending on the resultant frame rate.
I tried put this shader pack on my game but it doens't open and it gives me this error:
I'm sorry, but an uncaught exception occurred.
While running game code:
File "game/scripts/shaders/MVNRSP1.rpy", line 1, in script
init python:
File "game/scripts/shaders/MVNRSP1.rpy", line 1, in script
init python:
File "game/scripts/shaders/MVNRSP1.rpy", line 365, in <module>
renpy.register_shader("MakeVisualNovels.PerlinWarp",
Exception: MakeVisualNovels.PerlinWarp: Unknown shader variable line '//Commonly used variables in nearly all shaders.'. Only the form '{uniform,attribute,vertex} {type} {name} is allowed.
-- Full Traceback ------------------------------------------------------------
Full traceback:
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\bootstrap.py", line 277, in bootstrap
renpy.main.main()
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\main.py", line 558, in main
renpy.game.context().run(node)
File "game/scripts/shaders/MVNRSP1.rpy", line 1, in script
init python:
File "/home/tom/ab/renpy-build/tmp/install.linux-x86_64/lib/python3.9/site-packages/future/utils/__init__.py", line 441, in raise_
File "game/scripts/shaders/MVNRSP1.rpy", line 1, in script
init python:
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\ast.py", line 1131, in execute
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\python.py", line 1061, in py_exec_bytecode
exec(bytecode, globals, locals)
File "game/scripts/shaders/MVNRSP1.rpy", line 365, in <module>
renpy.register_shader("MakeVisualNovels.PerlinWarp",
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\gl2\gl2shadercache.py", line 48, in register_shader
ShaderPart(name, **kwargs)
File "D:\Renpy\Renpy 8-1.5.22-sdk\renpy\gl2\gl2shadercache.py", line 117, in __init__
raise Exception("{}: Unknown shader variable line {!r}. Only the form '{{uniform,attribute,vertex}} {{type}} {{name}} is allowed.".format(self.name, l))
Exception: MakeVisualNovels.PerlinWarp: Unknown shader variable line '//Commonly used variables in nearly all shaders.'. Only the form '{uniform,attribute,vertex} {type} {name} is allowed.
Windows-10-10.0.19041 AMD64
Ren'Py 8.0.3.22090809
The Raining Night
Sat Dec 14 00:14:10 2024
From the looks of it, your version of RenPy doesn't seem to like comments inside of the shader variable declaration, which is pretty odd. I would recommend updating to the newest version of RenPy and seeing if the issue persists.
Thanks for your work!
This is really cool! I wonder if there is a way to combine two shaders at once (say, Regicide and Animated Aberration) without getting the variables (uv, usually) clash?
There's a few ways to combine them, though I can't say I've looked too deeply about how they all look together.
The first way would be to apply one of the shaders to a layer and another shader to the displayables themselves. In doing that you can sort of stack two shaders together. RenPy docs on Layers here: https://www.renpy.org/doc/html/displaying_images.html#layer
The other way would be to directly edit the shader code to produce both effects, which I wouldn't recommend unless you're comfortable with writing shaders.
Right. The layer + displayable combo works, thank you. I don’t think you’d want to be too crazy with the combinations anyway, this is partly fuelled by sheer curiosity xD
I’m using this shader pack in my newest game, and it works smoothly on my laptop and on Renpy’s Android emulator. However, when running it on my phone (Xiaomi POCO M5 running on Xiaomi HyperOS 1.0.5.0 and Android version 14 UP1A.231005.007), I keep getting this error.
ShaderError: 0.39:S0001: Type mismatch in arithmetic operation between vec2 and int
Upon close inspection, it seems that this is primarily caused by the Regicide shader.Is there anything I can do to address this problem? (I am fairly comfortable with coding, but my knowledge of shader is limited to porting shadertoy examples to Ren’py)
I don't have the code right in front of me, but if I had to guess the error is likely coming from an instance where we're multiplying or dividing a full integer (eg.: 8) instead of a float/double (e.g 8.0) or vec2 (e.g, (8.0 , 8.0)) I can't recall any specific instance where I did that, but that's where I would start looking.
Normally I'd jump in to assist directly, but I'm presently drowning in event prep work for the Spooktober VN Jam and likely won't have time to do a full dive with you for at least a few weeks. Let me know what you find in a reply here and I'll do my best to offer suggestions during my down time.
Thank you for your pointer! It’s alright, I will not expect you to do so, and I’ll likely just put the Android version on the backburner if I can’t find a way to solve this. I’ll tell you what I find, but please don’t feel like there’s any pressure to reply! (Also, Regicide slaps, and I’ve been enjoying the Animated Aberration quite a bit too)
You’re right on the money! The u_scale and u_flipScale in the file MVNTemplates.rpy are integers, and changing them to floats solve the problem! Thank you very much!
Awesome, glad that was the right direction! Looking forward to seeing what you make!
Hi! Thank you very much for your shaders, they've been very helpful.
For some reason SimulatedLighting looks pixelated on my sprite ( link ). I've done some digging and it seems like
vec4 color = texture2D(tex0, uv);
is the problem. If I just set the gl_FragColor to color (literally gl_FragColor = color; ) it still is pixelated, just without the shader effect (obviously).
I am not sure what is the problem, but my sprites have quite a large resolution (though, changing it from 2000x1000 to 1000x500 didn't really help), so maybe resolution is the problem??? Renpy sometimes works in strange ways when sprites are too big. Or maybe (probably) it's something else, I don't know.
Well, anyway, I've found a solution. the color variable is only used in calculating the final color, so I just replaced the final line in the fragment shader to this:
gl_FragColor.rgb += fill_light_contribution + back_light_contribution + key_light_contribution;
And it looks ok ( link ), though, there are no alpha channel in it, but it works for me I guess ¯\_(ツ)_/¯.
Just wanted to leave it here in case anyone else has any similar problems, thanks again.
UPD: Just found an even better way to fix it!
Just change the color definition to:
vec4 color = gl_FragColor;
and it seems to work! Suprisingly simple, I guess, renpy doesn't like texture2D function? Anyway, it should (haven't checked) even work with the alpha channel now. Good luck.
Weeeird. I wish I had a picture of your sprite without influence from the shader so I could get a better idea of how things are changing.
You clearly know this because since you knew setting the output(gl_FragColor) to what you sampled would effectively disable any shader effects, but for everyone else: texture2d() is a function that returns a pixel(the color) at a given coordinate (uv) from a supplied texture, or tex0 as it's called in RenPy.
vec4 color = texture2d(tex0,uv) in this case would be the pixel color information from the source texture/image.
Shaders would then typically operate on, or using, this information to eventually assign it to the output, gl_FragColor. So in testing:
and still came up with artifacts is odd. I had spoken to Fen (go check them out btw they're awesome) and I recall something about v_tex_coord needing to be set to a_tex_coord in the Vertex shader-- I might be misremembering the details but if you're still getting those weird artifacts on your outputs when setting the input to the output (almost) directly, then we can really only assume that either the source texture or the coordinates are the problem.
I don't have it right in front of me at the moment, but if you're still toying with it and are familiar with it, it might be worth adding
into the vertex shader and trying again. I'm about 80% sure I'm using v_tex_coord as UV, which feels like the most likely culprit.
If you're able to try and confirm it, I can add a correction into the pack pretty quick to prevent anyone else from running into the problem. Otherwise I'll see if I can reproduce and fix it when I have time. I'm currently drowning in VN dev, several new packs, Spooktober Jam scouting and prep, and a half dozen IRL things so I don't know when exactly I'll get to it.
It's okay, don't rush it, I found a solution for me (mentioned in the edit above, setting color to gl_FragColor). Thanks for your response.
Here is the sprite link, though, as it turned out it doesn't matter really.
I've made a sample project to show it off link. I did it here with a standart sprite from "The Question", which is 500x700, so resolution isn't the problem, I guess.
And sadly no, setting v_tex_coord to a_tex_coord doesn't help. Really, it seems like a problem with renpy? I will open an issue on github some days later if we will not figure out the cause.
I also thought that it maybe show like that only when redacting the game project, but no, it is the same when the game is build, so it is either a problem with the shader (somehow?), renpy or my gpu (probably not, but would be nice to know if it's the same on your pc, there's always a chance, it is AMD by the way).
Update: just asked my friend has an Nvidia 1060 and it looks okay on his pc, I have an RX 6600 and it looks blurry...
Update2: opened an issue on Github link
Hi again! I was able to fix this issue with help from github (the issue).
Turns out, on some gpus the bias in texture2D defaults to a bad value. You would need to add u_lod_bias
uniform float u_lod_bias;
to the variables and to the texture2D function:
texture2D(tex0, v_tex_coord,u_lod_bias);
Nice. I'll see about working that into an update on the pack. I appreciate it!
Amazing shaders! Is there a way to modify the time of, for example, the AnimatedAberration? I don't know much about shaders. I saw a u_time variable, and I tried many things but couldn't make it work.
Excelent job, thank you so much!
PD: I was able to do it using normal animation methods, using StillAberration! Thanks!
Yep! So nearly any property that is supplied by the transform can be animated using the animation command. Good job on figuring out a way forward on it!
Ironically, it's harder to animate AnimatedAberration than it is to animate the still version of it from the outside. AnimatedAberration takes u_time into consideration, which is a uniform property that is representative of ongoing time. If you were able to set u_time to a constant value, it would.. actually stop animating! The changing of u_time as supplied by RenPy and the shader's uptime is actually driving that one's particular animation.
You could still animate Animated Aberration from the outside, but you'd only be able to animate the other exposed properties, and it probably would be hard to fine tune the appearance because the animation is baked into the shader itself for that one.
It was smart to go to the still version of it, because now you have significantly more control over how it behaves from the outside using the animation commands in RenPy. What you're doing is changing the values supplied by the transform directly, rather than having the shader calculate the latest step there.
I'd love to see how you did it, and I'm sure some other folks would too if you'd like to share.
I was able to make something like this, thanks to the shaders; thanks!
(The video looks kinda buggy)
To animate it, I basically did this;
Ignore the function thing. That's basically it!
I'll keep using the shaders on other displayables, thanks!
I'm still knee-deep in dev, but your VHS filter is really helping me sell this aspect ratio change in the middle of my current game. Thank you so much for making these and sharing them! I feel like they've taken me a layer deeper into understanding what Ren'Py can do.
Wow! Looks fantastic!
Is there a way to use it for the whole screen and not only on the character's sprites?
Yep! You can apply the premade transforms to backgrounds, characters, or entire layers.
I have an update that will include an example of this, but in the mean time you can set the Mesh property to true on a layer(or a transform you make/edit) and apply it to an entire layer, which can include anything on the screen that you add to it.
The master layer is the one you'd want to apply a transform to most of the time, if you're doing screen wide shaders.
Great! Thank you very much!
thanks for the awesome resource!
You're very welcome! I hope to bring more soon!
thank you so much for this can't wait to try it out!
I hope you're able to get the look you're after with these shaders! Thanks so much for checking them out!
Can't wait to try these out, thank you so much!
And I can't wait to see what awesome things you do with them! You're welcome to share pictures here of anything you guys make with them!
My game's lighting just got even more bisexual, thank you!
Also, a note for anyone using layeredimages: You'll probably want to add mesh True to the transform!
Compared to before (with manual airbrushing):
Does there happen to be a way to set the colors based on the state of another variable? My game keeps track of which floor you're currently on, and each floor has different lighting conditions. If it was possible to apply the "right" lighting automatically, this would be a huge game changer. :O
Wow! It's looking great! And yes, I've actually thought about making a mention to folks using layered sprites to use that since I've had a few people come back and ask how to sort it out.
As for using a variable to adjust the lighting, you could do it with a custom written transform that accepts a variable parameters instead of hard coded ones. I'll be working on another pack on stream this week, so I'll put some time into getting an example for you to play with on Tuesday!
Thank you so much, looking forward to it! :D
These shaders are exceptionally well researched and look great. Regicide is my favourite one. This is a top class resource for VN developers!
Thanks Endi! I hope you're able to get a lot of mileage out of them!