Start of the rewrite to a modular system
This commit is contained in:
parent
2bfdc30caa
commit
4ac45367e5
29 changed files with 4414 additions and 588 deletions
205
static/js/button-generator/effects/EXAMPLE.js
Normal file
205
static/js/button-generator/effects/EXAMPLE.js
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/**
|
||||
* EXAMPLE EFFECT
|
||||
*
|
||||
* This is a template for creating new effects.
|
||||
* Copy this file and modify it to create your own custom effects.
|
||||
*
|
||||
* This example creates a "spotlight" effect that highlights a circular area
|
||||
* and darkens the rest of the button.
|
||||
*/
|
||||
|
||||
import { ButtonEffect } from '../effect-base.js';
|
||||
|
||||
/**
|
||||
* Spotlight Effect
|
||||
* Creates a moving circular spotlight that highlights different areas
|
||||
*/
|
||||
export class SpotlightEffect extends ButtonEffect {
|
||||
constructor() {
|
||||
super({
|
||||
// Unique ID for this effect (used in control IDs)
|
||||
id: 'spotlight',
|
||||
|
||||
// Display name shown in UI
|
||||
name: 'Spotlight',
|
||||
|
||||
// Effect type determines render order category
|
||||
// Options: 'background', 'border', 'text', 'text2', 'general'
|
||||
type: 'general',
|
||||
|
||||
// Category for organizing effects in UI
|
||||
category: 'Visual Effects',
|
||||
|
||||
// Render order within type (lower = earlier)
|
||||
// 1-9: backgrounds, 10-19: borders, 20-29: transforms,
|
||||
// 30-49: text, 50-79: overlays, 80-99: post-processing
|
||||
renderOrder: 60
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Define UI controls for this effect
|
||||
* These controls will be automatically bound to the generator
|
||||
*/
|
||||
defineControls() {
|
||||
return [
|
||||
// Main enable/disable checkbox
|
||||
{
|
||||
id: 'animate-spotlight',
|
||||
type: 'checkbox',
|
||||
label: 'Spotlight Effect',
|
||||
defaultValue: false,
|
||||
description: 'Moving circular spotlight'
|
||||
},
|
||||
|
||||
// Spotlight size control
|
||||
{
|
||||
id: 'spotlight-size',
|
||||
type: 'range',
|
||||
label: 'Spotlight Size',
|
||||
defaultValue: 20,
|
||||
min: 10,
|
||||
max: 50,
|
||||
step: 1,
|
||||
showWhen: 'animate-spotlight', // Only show when checkbox is enabled
|
||||
description: 'Radius of the spotlight'
|
||||
},
|
||||
|
||||
// Darkness of the vignette
|
||||
{
|
||||
id: 'spotlight-darkness',
|
||||
type: 'range',
|
||||
label: 'Darkness',
|
||||
defaultValue: 0.5,
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.05,
|
||||
showWhen: 'animate-spotlight',
|
||||
description: 'How dark the non-spotlight area should be'
|
||||
},
|
||||
|
||||
// Speed of movement
|
||||
{
|
||||
id: 'spotlight-speed',
|
||||
type: 'range',
|
||||
label: 'Movement Speed',
|
||||
defaultValue: 1,
|
||||
min: 0.1,
|
||||
max: 3,
|
||||
step: 0.1,
|
||||
showWhen: 'animate-spotlight',
|
||||
description: 'Speed of spotlight movement'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this effect should be applied
|
||||
* @param {Object} controlValues - Current values of all controls
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isEnabled(controlValues) {
|
||||
return controlValues['animate-spotlight'] === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the effect to the canvas
|
||||
*
|
||||
* @param {CanvasRenderingContext2D} context - Canvas 2D rendering context
|
||||
* @param {Object} controlValues - Current values of all controls
|
||||
* @param {AnimationState|null} animState - Animation state (null for static render)
|
||||
* @param {Object} renderData - Render information: { width, height, centerX, centerY }
|
||||
*/
|
||||
apply(context, controlValues, animState, renderData) {
|
||||
// Skip if no animation (spotlight needs movement)
|
||||
if (!animState) return;
|
||||
|
||||
// Get control values
|
||||
const size = controlValues['spotlight-size'] || 20;
|
||||
const darkness = controlValues['spotlight-darkness'] || 0.5;
|
||||
const speed = controlValues['spotlight-speed'] || 1;
|
||||
|
||||
// Calculate spotlight position
|
||||
// Move in a circular pattern using animation phase
|
||||
const phase = animState.getPhase(speed);
|
||||
const spotX = renderData.centerX + Math.cos(phase) * 20;
|
||||
const spotY = renderData.centerY + Math.sin(phase) * 10;
|
||||
|
||||
// Create radial gradient for spotlight effect
|
||||
const gradient = context.createRadialGradient(
|
||||
spotX, spotY, 0, // Inner circle (center of spotlight)
|
||||
spotX, spotY, size // Outer circle (edge of spotlight)
|
||||
);
|
||||
|
||||
// Center is transparent (spotlight is bright)
|
||||
gradient.addColorStop(0, `rgba(0, 0, 0, 0)`);
|
||||
// Edge fades to dark
|
||||
gradient.addColorStop(0.5, `rgba(0, 0, 0, ${darkness * 0.3})`);
|
||||
gradient.addColorStop(1, `rgba(0, 0, 0, ${darkness})`);
|
||||
|
||||
// Apply the gradient as an overlay
|
||||
context.fillStyle = gradient;
|
||||
context.fillRect(0, 0, renderData.width, renderData.height);
|
||||
|
||||
// Optional: Add a bright center dot
|
||||
context.fillStyle = 'rgba(255, 255, 255, 0.3)';
|
||||
context.beginPath();
|
||||
context.arc(spotX, spotY, 2, 0, Math.PI * 2);
|
||||
context.fill();
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: Override canApply for more complex logic
|
||||
* By default, it just checks isEnabled()
|
||||
*/
|
||||
canApply(controlValues) {
|
||||
// Example: Only apply if text is also enabled
|
||||
const textEnabled = controlValues['textEnabled'];
|
||||
return this.isEnabled(controlValues) && textEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional: Add helper methods for your effect
|
||||
*/
|
||||
calculateSpotlightPath(progress, width, height) {
|
||||
// Example helper method
|
||||
return {
|
||||
x: width * progress,
|
||||
y: height / 2
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registration function
|
||||
* This is called to add the effect to the generator
|
||||
*
|
||||
* @param {ButtonGenerator} generator - The button generator instance
|
||||
*/
|
||||
export function register(generator) {
|
||||
generator.registerEffect(new SpotlightEffect());
|
||||
}
|
||||
|
||||
/**
|
||||
* USAGE:
|
||||
*
|
||||
* 1. Copy this file to a new name (e.g., my-effect.js)
|
||||
* 2. Modify the class name, id, and effect logic
|
||||
* 3. Import in main.js:
|
||||
* import * as myEffect from './effects/my-effect.js';
|
||||
* 4. Register in setupApp():
|
||||
* myEffect.register(generator);
|
||||
* 5. Add HTML controls with matching IDs
|
||||
*/
|
||||
|
||||
/**
|
||||
* TIPS:
|
||||
*
|
||||
* - Use animState.progress for linear animations (0 to 1)
|
||||
* - Use animState.getPhase(speed) for periodic animations (0 to 2π)
|
||||
* - Use Math.sin/cos for smooth periodic motion
|
||||
* - Check if (!animState) at the start if your effect requires animation
|
||||
* - The context is automatically saved/restored, so feel free to transform
|
||||
* - Use renderData for canvas dimensions and center point
|
||||
* - Look at existing effects for more examples
|
||||
*/
|
||||
Loading…
Add table
Add a link
Reference in a new issue