# Aura Glow
Looks really cool! I think the defaults could be a bit more "spectacular". More color speed (5?) and less saturation (0.5?) looks much better in my opinion.
There is a significant delay when closing a window before the animation starts. Can this be removed?
Is a saturation > 1 useful?

✅ Color Speed = 5
✅ Saturation at 0.5
❓ the delay ...
i think this was caused by the padding
i tried to get rid of it in the shader (see "//adjust for gnome" in the shader).
maybe you know a better way .
✅ Is a saturation > 1 useful?
... i guess not 😀

# Mushroom
Aweome!
Only complaint: The preset dropdown says "8Bit Plumber (default)" but the default is actually "New Bros 2".

✅ fixed, i'll just take the word "default" out

# RGB Warp
The defaults look great!
I would rename it to "RGB Warp" instead of "RGB Warp Effect" to be consistent with the other effects.
All the settings in the UI could use some spaces.
Is the Wave Size parameter useful? Any other values than 1 look pretty weird.

✅
✅
✅ wavesize ... it was more useful in shadertoy, when it was there, removed.

# TeamRocket
The best one in my opinion!
I would call it "Team Rocket" instead of "TeamRocket" to be consistent with the other effects.
I would enable window rotation per default and set the Y value to a value other than 0, maybe 0.5. This makes it a bit more organic!

✅
✅

# UnicornFart
Here I have severe performance issues. On my machine, the effect is not usable. Even with only 10 stars and sparks, I only get a few FPS. What shall we do about this? I think we either need to optimize this or think about a different effect. I liked your initial idea with the wobbly rgb noise as well...
Anyways, great work! I am really looking forward to this! Let me know what you think about these points, and then I'll soon have a look at the individual effect implementations.

ok, i'll take this out and try something else.
...maybe i shouldn't have used the blur on it.
👍👍👍
This commit is contained in:
Justin Garza
2025-01-24 18:50:15 -05:00
parent dd49880638
commit 4b8124c5bb
13 changed files with 17 additions and 1758 deletions
+1 -1
View File
@@ -201,7 +201,7 @@ export default class Effect {
// format).
const presets = [
{
name: _('8Bit Plumber (Default)'),
name: _('8Bit Plumber'),
ScaleStyle: 0.0,
SparkCount: 0,
SparkColor: 'rgba(255,255,255,0.0)',
+1 -6
View File
@@ -38,7 +38,6 @@ export default class Effect {
constructor() {
this.shaderFactory = new ShaderFactory(Effect.getNick(), (shader) => {
// Store uniform locations of newly created shaders.
shader._uWavesize = shader.get_uniform_location('uWavesize');
shader._uBrightness = shader.get_uniform_location('uBrightness');
shader._uStretchR = shader.get_uniform_location('uStretchR');
shader._uStretchG = shader.get_uniform_location('uStretchG');
@@ -46,9 +45,6 @@ export default class Effect {
// Write all uniform values at the start of each animation.
shader.connect('begin-animation', (shader, settings) => {
shader.set_uniform_float(shader._uWavesize, 1, [
settings.get_double('rgbwarp-wavesize'),
]);
shader.set_uniform_float(shader._uBrightness, 1, [
settings.get_double('rgbwarp-brightness'),
@@ -88,7 +84,7 @@ export default class Effect {
// This will be shown in the sidebar of the preferences dialog as well as in the
// drop-down menus where the user can choose the effect.
static getLabel() {
return _('RGB Warp Effect');
return _('RGB Warp');
}
// -------------------------------------------------------------------- API for prefs.js
@@ -99,7 +95,6 @@ export default class Effect {
// Empty for now... Code is added here later in the tutorial!
dialog.bindAdjustment('rgbwarp-animation-time');
dialog.bindAdjustment('rgbwarp-wavesize');
dialog.bindAdjustment('rgbwarp-brightness');
dialog.bindAdjustment('rgbwarp-offset-r');
dialog.bindAdjustment('rgbwarp-offset-g');
+1 -1
View File
@@ -99,7 +99,7 @@ export default class Effect {
// This will be shown in the sidebar of the preferences dialog as well as in the
// drop-down menus where the user can choose the effect.
static getLabel() {
return _('TeamRocket');
return _('Team Rocket');
}
// -------------------------------------------------------------------- API for prefs.js
-471
View File
@@ -1,471 +0,0 @@
//////////////////////////////////////////////////////////////////////////////////////////
// ) ( //
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
// |__/ //
//////////////////////////////////////////////////////////////////////////////////////////
// SPDX-FileCopyrightText: Justin Garza JGarza9788@gmail.com
// SPDX-License-Identifier: GPL-3.0-or-later
'use strict';
// Import the Gio module from the GNOME platform (GObject Introspection).
// This module provides APIs for I/O operations, settings management, and other core
// features.
import Gio from 'gi://Gio';
// Import utility functions from the local utils.js file.
// These utilities likely contain helper functions or shared logic used across the
// application.
import * as utils from '../utils.js';
// We import the ShaderFactory only in the Shell process as it is not required in the
// preferences process. The preferences process does not create any shader instances, it
// only uses the static metadata of the effect.
const ShaderFactory = await utils.importInShellOnly('./ShaderFactory.js');
const _ = await utils.importGettext();
//////////////////////////////////////////////////////////////////////////////////////////
// I thought to myself, i said "self what would a unicorn fart look like" and then i came
// up with this, and i don't care that i'm out of the box, i think outside of the box,
// yeah f*ck that box!
//////////////////////////////////////////////////////////////////////////////////////////
// The effect class can be used to get some metadata (like the effect's name or supported
// GNOME Shell versions), to initialize the respective page of the settings dialog, as
// well as to create the actual shader for the effect.
export default class Effect {
// The constructor creates a ShaderFactory which will be used by extension.js to create
// shader instances for this effect. The shaders will be automagically created using the
// GLSL file in resources/shaders/<nick>.glsl. The callback will be called for each
// newly created shader instance.
constructor() {
this.shaderFactory = new ShaderFactory(Effect.getNick(), (shader) => {
// Store uniform locations of newly created shaders.
// shader._uParticles = shader.get_uniform_location('uParticles');
// shader._uParticleSize = shader.get_uniform_location('uParticleSize');
// shader._uParticleSpeed = shader.get_uniform_location('uParticleSpeed');
// shader._uParticleColorRandom =
// shader.get_uniform_location('uParticleColorRandom'); shader._uParticleColorSpeed
// = shader.get_uniform_location('uParticleColorSpeed');
shader._uSparkCount = shader.get_uniform_location('uSparkCount');
shader._uSparkStartEnd = shader.get_uniform_location('uSparkStartEnd');
shader._uSparkOffset = shader.get_uniform_location('uSparkOffset');
shader._uSparkCount = shader.get_uniform_location('uSparkCount');
shader._uStarCount = shader.get_uniform_location('uStarCount');
shader._uStarRot = shader.get_uniform_location('uStarRot');
shader._uStarSize = shader.get_uniform_location('uStarSize');
shader._uStarStartEnd = shader.get_uniform_location('uStarStartEnd');
shader._uBlurQuality = shader.get_uniform_location('uBlurQuality');
shader._uSeed = shader.get_uniform_location('uSeed');
shader._uStarColors = [
shader.get_uniform_location('uStarColor0'),
shader.get_uniform_location('uStarColor1'),
shader.get_uniform_location('uStarColor2'),
shader.get_uniform_location('uStarColor3'),
shader.get_uniform_location('uStarColor4'),
shader.get_uniform_location('uStarColor5'),
];
shader._uParticleColors = [
shader.get_uniform_location('uSparkColor0'),
shader.get_uniform_location('uSparkColor1'),
shader.get_uniform_location('uSparkColor2'),
shader.get_uniform_location('uSparkColor3'),
shader.get_uniform_location('uSparkColor4'),
shader.get_uniform_location('uSparkColor5'),
];
// Write all uniform values at the start of each animation.
shader.connect('begin-animation', (shader, settings) => {
for (let i = 0; i <= 5; i++) {
shader.set_uniform_float(
shader._uStarColors[i], 4,
utils.parseColor(settings.get_string('unicorn-fart-star-color-' + i)));
}
for (let i = 0; i <= 5; i++) {
shader.set_uniform_float(
shader._uParticleColors[i], 4,
utils.parseColor(settings.get_string('unicorn-fart-spark-color-' + i)));
}
shader.set_uniform_float(shader._uSparkCount, 1,
[settings.get_int('unicorn-fart-spark-count')]);
shader.set_uniform_float(shader._uSparkStartEnd, 2, [
settings.get_double('unicorn-fart-spark-start'),
settings.get_double('unicorn-fart-spark-end')
]);
shader.set_uniform_float(shader._uSparkOffset, 1,
[settings.get_double('unicorn-fart-spark-offset')]);
shader.set_uniform_float(shader._uStarCount, 1,
[settings.get_int('unicorn-fart-star-count')]);
shader.set_uniform_float(shader._uStarRot, 1,
[settings.get_double('unicorn-fart-star-rotation')]);
shader.set_uniform_float(shader._uStarSize, 1,
[settings.get_double('unicorn-fart-star-size')]);
shader.set_uniform_float(shader._uStarStartEnd, 2, [
settings.get_double('unicorn-fart-star-start'),
settings.get_double('unicorn-fart-star-end')
]);
shader.set_uniform_float(shader._uBlurQuality, 1,
[settings.get_double('unicorn-fart-blur-quality')]);
shader.set_uniform_float(shader._uSeed, 1, [Math.random()]);
});
});
}
// ---------------------------------------------------------------------------- metadata
// The effect is available on all GNOME Shell versions supported by this extension.
static getMinShellVersion() {
return [3, 36];
}
// This will be called in various places where a unique identifier for this effect is
// required. It should match the prefix of the settings keys which store whether the
// effect is enabled currently (e.g. '*-enable-effect'), and its animation time
// (e.g. '*-animation-time'). Also, the shader file and the settings UI files should be
// named likes this.
static getNick() {
return 'unicorn-fart';
}
// This will be shown in the sidebar of the preferences dialog as well as in the
// drop-down menus where the user can choose the effect.
static getLabel() {
return _('UnicornFart');
}
// -------------------------------------------------------------------- API for prefs.js
// This is called by the preferences dialog whenever a new effect profile is loaded. It
// binds all user interface elements to the respective settings keys of the profile.
static bindPreferences(dialog) {
// Empty for now... Code is added here later in the tutorial!
dialog.bindAdjustment('unicorn-fart-animation-time');
dialog.bindAdjustment('unicorn-fart-spark-count');
dialog.bindAdjustment('unicorn-fart-spark-start');
dialog.bindAdjustment('unicorn-fart-spark-end');
dialog.bindAdjustment('unicorn-fart-spark-offset');
dialog.bindAdjustment('unicorn-fart-star-count');
dialog.bindAdjustment('unicorn-fart-star-rotation');
dialog.bindAdjustment('unicorn-fart-star-size');
dialog.bindAdjustment('unicorn-fart-star-start');
dialog.bindAdjustment('unicorn-fart-star-end');
dialog.bindAdjustment('unicorn-fart-blur-quality');
// switches
dialog.bindSwitch('unicorn-fart-particles-enable');
// star-color
dialog.bindColorButton('unicorn-fart-star-color-0');
dialog.bindColorButton('unicorn-fart-star-color-1');
dialog.bindColorButton('unicorn-fart-star-color-2');
dialog.bindColorButton('unicorn-fart-star-color-3');
dialog.bindColorButton('unicorn-fart-star-color-4');
dialog.bindColorButton('unicorn-fart-star-color-5');
// particle-colors
dialog.bindColorButton('unicorn-fart-spark-color-0');
dialog.bindColorButton('unicorn-fart-spark-color-1');
dialog.bindColorButton('unicorn-fart-spark-color-2');
dialog.bindColorButton('unicorn-fart-spark-color-3');
dialog.bindColorButton('unicorn-fart-spark-color-4');
dialog.bindColorButton('unicorn-fart-spark-color-5');
// Ensure the button connections and other bindings happen only once,
// even if the bindPreferences function is called multiple times.
if (!Effect._isConnected) {
Effect._isConnected = true;
// Bind the "reset-unicorn-fart-spark-colors" button to reset all star colors to
// their default values.
dialog.getBuilder()
.get_object('reset-unicorn-fart-spark-colors')
.connect('clicked', () => {
// Reset each mushroom star color setting.
dialog.getProfileSettings().reset('unicorn-fart-spark-color-0');
dialog.getProfileSettings().reset('unicorn-fart-spark-color-1');
dialog.getProfileSettings().reset('unicorn-fart-spark-color-2');
dialog.getProfileSettings().reset('unicorn-fart-spark-color-3');
dialog.getProfileSettings().reset('unicorn-fart-spark-color-4');
dialog.getProfileSettings().reset('unicorn-fart-spark-color-5');
});
dialog.getBuilder()
.get_object('reset-unicorn-fart-star-colors')
.connect('clicked', () => {
// Reset each mushroom star color setting.
dialog.getProfileSettings().reset('unicorn-fart-star-color-0');
dialog.getProfileSettings().reset('unicorn-fart-star-color-1');
dialog.getProfileSettings().reset('unicorn-fart-star-color-2');
dialog.getProfileSettings().reset('unicorn-fart-star-color-3');
dialog.getProfileSettings().reset('unicorn-fart-star-color-4');
dialog.getProfileSettings().reset('unicorn-fart-star-color-5');
});
// Initialize the preset dropdown menu for mushroom star colors.
Effect._createUnicornFartPresets(dialog);
}
}
// ---------------------------------------------------------------- API for extension.js
// The getActorScale() is called from extension.js to adjust the actor's size during the
// animation. This is useful if the effect requires drawing something beyond the usual
// bounds of the actor. This only works for GNOME 3.38+.
static getActorScale(settings, forOpening, actor) {
return {x: 2.0, y: 2.0};
}
// ---------------------------------------------------------------- Presets
// This function initializes the preset dropdown menu for configuring fire options.
// It defines multiple color presets for the "mushroom star" effect and sets up
// the logic to apply these presets when selected.
static _createUnicornFartPresets(dialog) {
// Retrieve the builder object for the dialog and connect to the "realize" event of
// the button.
dialog.getBuilder()
.get_object('unicorn-fart-preset-button')
.connect('realize', (widget) => {
// Define an array of color presets, each with a name and six color values (RGBA
// format).
const presets = [
{
name: _('Unicorn Fart (Default)'),
SparkCount: 25,
SparkStart: 0.0,
SparkEnd: 1.0,
SparkOffset: 1.0,
StarCount: 6,
StarRot: 0.33,
StarSize: 0.10,
StarStart: 0.0,
StarEnd: 1.0,
BlurQuality: 5.0,
Sparkcolor0: 'rgba(255,255,255,1.0)',
Sparkcolor1: 'rgba(255,255,255,1.0)',
Sparkcolor2: 'rgba(255,255,255,1.0)',
Sparkcolor3: 'rgba(255,255,255,1.0)',
Sparkcolor4: 'rgba(255,255,255,1.0)',
Sparkcolor5: 'rgba(255,255,255,1.0)',
Starcolor0: 'rgba(255,0,0,1.0)',
Starcolor1: 'rgba(255,255,0,1.0)',
Starcolor2: 'rgba(0,255,0,1.0)',
Starcolor3: 'rgba(0,255,255,1.0)',
Starcolor4: 'rgba(0,0,255,1.0)',
Starcolor5: 'rgba(255,0,255,1.0)',
},
{
name: _('Fairy🧚'),
SparkCount: 100,
SparkStart: 0.0,
SparkEnd: 1.0,
SparkOffset: 1.0,
StarCount: 0,
StarRot: 0.33,
StarSize: 0.10,
StarStart: 0.0,
StarEnd: 1.0,
BlurQuality: 5.0,
Sparkcolor0: 'rgba(255,255,255,1.0)',
Sparkcolor1: 'rgba(255,255,255,1.0)',
Sparkcolor2: 'rgba(255,255,255,1.0)',
Sparkcolor3: 'rgba(255,255,255,1.0)',
Sparkcolor4: 'rgba(255,255,255,1.0)',
Sparkcolor5: 'rgba(255,255,255,1.0)',
Starcolor0: 'rgba(255,0,0,1.0)',
Starcolor1: 'rgba(255,255,0,1.0)',
Starcolor2: 'rgba(0,255,0,1.0)',
Starcolor3: 'rgba(0,255,255,1.0)',
Starcolor4: 'rgba(0,0,255,1.0)',
Starcolor5: 'rgba(255,0,255,1.0)',
},
{
name: _('Ring of Fire ❤️‍🔥'),
SparkCount: 100,
SparkStart: 0.0,
SparkEnd: 1.0,
SparkOffset: 1.0,
StarCount: 25,
StarRot: 3.0,
StarSize: 0.10,
StarStart: 0.0,
StarEnd: 1.0,
BlurQuality: 5.0,
Sparkcolor0: 'rgba(255,0,0,1.0)', // Deep red
Sparkcolor1: 'rgba(255,69,0,1.0)', // Fiery orange-red
Sparkcolor2: 'rgba(255,140,0,1.0)', // Orange
Sparkcolor3: 'rgba(255,215,0,1.0)', // Bright yellow
Sparkcolor4: 'rgba(255,255,102,1.0)', // Light yellow
Sparkcolor5: 'rgba(255,255,255,1.0)', // White (hottest point)
Starcolor0: 'rgba(255,0,0,1.0)', // Deep red
Starcolor1: 'rgba(255,69,0,1.0)', // Fiery orange-red
Starcolor2: 'rgba(255,140,0,1.0)', // Orange
Starcolor3: 'rgba(255,215,0,1.0)', // Bright yellow
Starcolor4: 'rgba(255,255,102,1.0)', // Light yellow
Starcolor5: 'rgba(255,255,255,1.0)', // White (hottest point)
},
{
name: _('Mystic 🪄'),
SparkCount: 100,
SparkStart: 0.0,
SparkEnd: 1.0,
SparkOffset: 1.0,
StarCount: 25,
StarRot: 3.0,
StarSize: 0.10,
StarStart: 0.0,
StarEnd: 1.0,
BlurQuality: 5.0,
Sparkcolor0: 'rgba(75,0,130,1.0)', // Indigo
Sparkcolor1: 'rgba(138,43,226,1.0)', // Blue-violet
Sparkcolor2: 'rgba(0,191,255,1.0)', // Deep sky blue
Sparkcolor3: 'rgba(0,255,127,1.0)', // Spring green
Sparkcolor4: 'rgba(173,255,47,1.0)', // Green-yellow
Sparkcolor5: 'rgba(255,20,147,1.0)', // Deep pink
Starcolor0: 'rgba(75,0,130,1.0)', // Indigo
Starcolor1: 'rgba(138,43,226,1.0)', // Blue-violet
Starcolor2: 'rgba(0,191,255,1.0)', // Deep sky blue
Starcolor3: 'rgba(0,255,127,1.0)', // Spring green
Starcolor4: 'rgba(173,255,47,1.0)', // Green-yellow
Starcolor5: 'rgba(255,20,147,1.0)', // Deep pink
},
];
// Create a new menu model to hold the presets and an action group for handling
// selections.
const menu = Gio.Menu.new();
const group = Gio.SimpleActionGroup.new();
const groupName = 'presets';
// Iterate over the presets to populate the menu.
presets.forEach((preset, i) => {
// Define an action name based on the preset index.
const actionName = 'unicorn-fart' + i;
// Append the preset name to the menu.
menu.append(preset.name, groupName + '.' + actionName);
// Create a new action for the preset.
let action = Gio.SimpleAction.new(actionName, null);
// Connect the action to a function that loads the preset colors into the
// dialog.
action.connect('activate', () => {
dialog.getProfileSettings().set_int('unicorn-fart-spark-count',
preset.SparkCount);
dialog.getProfileSettings().set_double('unicorn-fart-spark-start',
preset.SparkStart);
dialog.getProfileSettings().set_double('unicorn-fart-spark-end',
preset.SparkEnd);
dialog.getProfileSettings().set_double('unicorn-fart-spark-offset',
preset.SparkOffset);
dialog.getProfileSettings().set_int('unicorn-fart-star-count',
preset.StarCount);
dialog.getProfileSettings().set_double('unicorn-fart-star-rotation',
preset.StarRot);
dialog.getProfileSettings().set_double('unicorn-fart-star-size',
preset.StarSize);
dialog.getProfileSettings().set_double('unicorn-fart-star-start',
preset.StarStart);
dialog.getProfileSettings().set_double('unicorn-fart-star-end',
preset.StarEnd);
dialog.getProfileSettings().set_double('unicorn-fart-blur-quality',
preset.BlurQuality);
dialog.getProfileSettings().set_string('unicorn-fart-spark-color-0',
preset.Sparkcolor0);
dialog.getProfileSettings().set_string('unicorn-fart-spark-color-1',
preset.Sparkcolor1);
dialog.getProfileSettings().set_string('unicorn-fart-spark-color-2',
preset.Sparkcolor2);
dialog.getProfileSettings().set_string('unicorn-fart-spark-color-3',
preset.Sparkcolor3);
dialog.getProfileSettings().set_string('unicorn-fart-spark-color-4',
preset.Sparkcolor4);
dialog.getProfileSettings().set_string('unicorn-fart-spark-color-5',
preset.Sparkcolor5);
dialog.getProfileSettings().set_string('unicorn-fart-star-color-0',
preset.Starcolor0);
dialog.getProfileSettings().set_string('unicorn-fart-star-color-1',
preset.Starcolor1);
dialog.getProfileSettings().set_string('unicorn-fart-star-color-2',
preset.Starcolor2);
dialog.getProfileSettings().set_string('unicorn-fart-star-color-3',
preset.Starcolor3);
dialog.getProfileSettings().set_string('unicorn-fart-star-color-4',
preset.Starcolor4);
dialog.getProfileSettings().set_string('unicorn-fart-star-color-5',
preset.Starcolor5);
});
// Add the action to the action group.
group.add_action(action);
});
// Assign the populated menu to the preset button.
dialog.getBuilder().get_object('unicorn-fart-preset-button').set_menu_model(menu);
// Insert the action group into the root widget for handling the presets.
const root = widget.get_root();
root.insert_action_group(groupName, group);
});
}
}