help@rskworld.in +91 93305 39277
RSK World
  • Home
  • Development
    • Web Development
    • Mobile Apps
    • Software
    • Games
    • Project
  • Technologies
    • Data Science
    • AI Development
    • Cloud Development
    • Blockchain
    • Cyber Security
    • Dev Tools
    • Testing Tools
  • Blog
  • About
  • Contact

Theme Settings

Color Scheme
Display Options
Font Size
100%
Back to Project
RSK World
star-pattern-maker
/
js
RSK World
star-pattern-maker
Star Pattern Maker - HTML5 Canvas + 3D Rendering + Physics Simulation + AI Patterns + Generative Audio + Modern UI + Glassmorphism Design
js
  • 3d-engine.js3.8 KB
  • ai-patterns.js5.6 KB
  • animations.js1.4 KB
  • audio.js1.3 KB
  • controls.js12.2 KB
  • export.js3.9 KB
  • filters.js3.5 KB
  • fractals.js3.5 KB
  • gallery.js2.5 KB
  • main.js1.9 KB
  • particles.js1.4 KB
  • physics.js1.7 KB
  • presets.js2.8 KB
  • randomizer.js1.4 KB
  • renderer.js7 KB
  • shaders.js6.5 KB
  • shapes.js1.7 KB
  • sound-gen.js4.4 KB
  • state.js1.9 KB
  • symmetry.js3.9 KB
  • themes.js1.4 KB
  • timeline.js4.2 KB
  • utils.js546 B
syntax_checker.cpython-313.pycphysics.js3d-engine.jsrenderer.jscontrols.js
js/physics.js
Raw Download
Find: Go to:
/* V12 Physics Module */
import { state } from './state.js';

// Gravity state (persistent)
let velocityX = 0;
let velocityY = 0;
let offsetX = 0;
let offsetY = 0;

/**
 * Apply gravity pull toward mouse position
 * Returns offset to apply to star position
 */
export function applyGravity(canvasWidth, canvasHeight) {
    if (!state.gravityEnabled) {
        // Reset when disabled
        velocityX *= 0.95;
        velocityY *= 0.95;
        offsetX *= 0.95;
        offsetY *= 0.95;
        return { x: offsetX, y: offsetY };
    }

    // Target position (mouse or center)
    const targetX = state.mouseX || 0;
    const targetY = state.mouseY || 0;

    // Calculate attraction force
    const dx = targetX - offsetX;
    const dy = targetY - offsetY;
    const distance = Math.sqrt(dx * dx + dy * dy);

    if (distance > 5) {
        const force = 0.02; // Gravity strength
        const ax = (dx / distance) * force;
        const ay = (dy / distance) * force;

        velocityX += ax;
        velocityY += ay;
    }

    // Apply friction
    velocityX *= 0.98;
    velocityY *= 0.98;

    // Update position
    offsetX += velocityX;
    offsetY += velocityY;

    return { x: offsetX, y: offsetY };
}

/**
 * Calculate orbital position around center
 */
export function calculateOrbit(time, radius = 100) {
    if (!state.orbitEnabled) return { x: 0, y: 0 };

    const speed = 0.001; // Orbit speed
    const angle = time * speed;

    return {
        x: Math.cos(angle) * radius,
        y: Math.sin(angle) * radius
    };
}

/**
 * Reset physics state
 */
export function resetPhysics() {
    velocityX = 0;
    velocityY = 0;
    offsetX = 0;
    offsetY = 0;
}
77 lines•1.7 KB
javascript
js/3d-engine.js
Raw Download
Find: Go to:
/* V15 3D Engine Module - Pseudo-3D Rendering */
import { state } from './state.js';

/**
 * 3D Point class
 */
class Point3D {
    constructor(x, y, z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
}

/**
 * Project 3D point to 2D screen coordinates
 */
export function project3D(point, fov = 500, distance = 1000) {
    const scale = fov / (fov + point.z + distance);
    return {
        x: point.x * scale,
        y: point.y * scale,
        scale: scale
    };
}

/**
 * Rotate point around X axis
 */
function rotateX(point, angle) {
    const rad = angle * Math.PI / 180;
    const cos = Math.cos(rad);
    const sin = Math.sin(rad);

    return new Point3D(
        point.x,
        point.y * cos - point.z * sin,
        point.y * sin + point.z * cos
    );
}

/**
 * Rotate point around Y axis
 */
function rotateY(point, angle) {
    const rad = angle * Math.PI / 180;
    const cos = Math.cos(rad);
    const sin = Math.sin(rad);

    return new Point3D(
        point.x * cos + point.z * sin,
        point.y,
        -point.x * sin + point.z * cos
    );
}

/**
 * Rotate point around Z axis
 */
function rotateZ(point, angle) {
    const rad = angle * Math.PI / 180;
    const cos = Math.cos(rad);
    const sin = Math.sin(rad);

    return new Point3D(
        point.x * cos - point.y * sin,
        point.x * sin + point.y * cos,
        point.z
    );
}

/**
 * Apply all 3D rotations
 */
export function rotate3D(point, angleX, angleY, angleZ) {
    let p = point;
    if (angleX !== 0) p = rotateX(p, angleX);
    if (angleY !== 0) p = rotateY(p, angleY);
    if (angleZ !== 0) p = rotateZ(p, angleZ);
    return p;
}

/**
 * Generate 3D star points
 */
export function generate3DStarPoints(spikes, outerRadius, innerRadius) {
    const points = [];
    const step = Math.PI / spikes;

    for (let i = 0; i < spikes * 2; i++) {
        const angle = i * step - Math.PI / 2;
        const radius = i % 2 === 0 ? outerRadius : innerRadius;

        points.push(new Point3D(
            Math.cos(angle) * radius,
            Math.sin(angle) * radius,
            0
        ));
    }

    return points;
}

/**
 * Draw 3D star with rotation
 */
export function draw3DStar(ctx, w, h, rOuter, rInner) {
    const cx = w / 2;
    const cy = h / 2;

    // Generate star points
    let points = generate3DStarPoints(state.spikes, rOuter, rInner);

    // Apply 3D rotations
    points = points.map(p => rotate3D(
        p,
        state.rotation3DX || 0,
        state.rotation3DY || 0,
        state.rotation3DZ || 0
    ));

    // Project to 2D
    const projected = points.map(p => project3D(p));

    // Sort by Z-depth (painter's algorithm)
    const avgZ = points.reduce((sum, p) => sum + p.z, 0) / points.length;

    // Draw
    ctx.save();
    ctx.translate(cx, cy);

    ctx.beginPath();
    projected.forEach((p, i) => {
        if (i === 0) {
            ctx.moveTo(p.x, p.y);
        } else {
            ctx.lineTo(p.x, p.y);
        }
    });
    ctx.closePath();

    // Apply lighting based on Z-depth
    const brightness = 1 + (avgZ / 500);
    ctx.globalAlpha = Math.max(0.3, Math.min(1, brightness));

    ctx.fill();
    if (state.lineWidth > 0) ctx.stroke();

    ctx.restore();
}

/**
 * Update 3D rotation (called from animation loop)
 */
export function update3DRotation() {
    if (state.auto3DRotation) {
        state.rotation3DX = (state.rotation3DX || 0) + 0.5;
        state.rotation3DY = (state.rotation3DY || 0) + 0.3;
        state.rotation3DZ = (state.rotation3DZ || 0) + 0.2;

        // Keep angles in 0-360 range
        state.rotation3DX %= 360;
        state.rotation3DY %= 360;
        state.rotation3DZ %= 360;
    }
}
167 lines•3.8 KB
javascript
js/renderer.js
Raw Download
Find: Go to:
/* V7 Renderer Module */
import { state } from './state.js';
import { drawStarPath } from './shapes.js';
import { drawParticles } from './particles.js';
import { getAudioData } from './audio.js';
import { renderRecursiveFractal } from './fractals.js';
import { applyGravity, calculateOrbit } from './physics.js';
import { applyFilters } from './filters.js';
import { drawMandala, drawSpiral } from './symmetry.js';

export function draw(ctx, canvas) {
    const width = canvas.width;
    const height = canvas.height;

    // Clear & BG
    if (state.trailEnabled && state.speed > 0) {
        // Transparent clear for trails
        ctx.fillStyle = state.bgColor + '1a'; // ~10% opacity
        ctx.fillRect(0, 0, width, height);
    } else {
        ctx.clearRect(0, 0, width, height);
        if (state.bgColor) {
            ctx.fillStyle = state.bgColor;
            ctx.fillRect(0, 0, width, height);
        }
    }

    // Ambient Particles (Behind)
    drawParticles(ctx, width, height);

    // Core Styles
    ctx.lineJoin = 'round';
    ctx.strokeStyle = state.strokeColor;
    ctx.lineWidth = state.lineWidth;

    // Audio Mod
    let rOuter = state.outerRadius;
    let rInner = state.innerRadius;
    let glowVal = state.glow;

    if (state.audioMode) {
        const audio = getAudioData();
        if (audio) {
            const bassBoost = (audio.bass / 255) * 50;
            rOuter += bassBoost;
            rInner += (bassBoost / 2);
            if (state.glow > 0) glowVal += (audio.avg / 5);
        }
    }

    // Glow
    if (glowVal > 0) {
        ctx.shadowBlur = glowVal;
        ctx.shadowColor = state.strokeColor;
    } else {
        ctx.shadowBlur = 0;
        ctx.shadowColor = 'transparent';
    }

    // V8 Rainbow Flow (Dynamic Fill)
    let dynamicFill = null;
    if (state.rainbowMode) {
        const hue = (Date.now() / 20) % 360;
        dynamicFill = `hsl(${hue}, 70%, 50%)`;
    }

    // V8 Cosmic Pulse (Scale Mod)
    let pulseScale = 1;
    if (state.pulseEnabled) {
        pulseScale = 1 + Math.sin(Date.now() * 0.002) * 0.05;
    }

    // Apply pulse to radii
    rOuter *= pulseScale;
    rInner *= pulseScale;

    // V12 Physics (Gravity & Orbit)
    let physicsOffsetX = 0;
    let physicsOffsetY = 0;

    if (state.gravityEnabled) {
        const gravity = applyGravity(width, height);
        physicsOffsetX += gravity.x;
        physicsOffsetY += gravity.y;
    }

    if (state.orbitEnabled) {
        const orbit = calculateOrbit(Date.now(), 80);
        physicsOffsetX += orbit.x;
        physicsOffsetY += orbit.y;
    }

    // Draw Mode with Echoes (V11)
    const echoes = state.echoEnabled ? state.echoCount : 1;

    for (let i = 0; i < echoes; i++) {
        ctx.save();

        if (state.echoEnabled && i > 0) {
            const scale = 1 - (i * 0.1);
            const alpha = 1 - (i / echoes);
            ctx.scale(scale, scale);
            ctx.globalAlpha = alpha;
        }

        // V13 Symmetry Modes
        if (state.mandalaMode) {
            drawMandala(ctx, width, height, rOuter, rInner, dynamicFill);
        }
        else if (state.spiralMode) {
            drawSpiral(ctx, width, height, rOuter, rInner, dynamicFill);
        }
        // V6+ Modes
        else if (state.kaleidoscopeMode) {
            drawKaleidoscope(ctx, width, height, rOuter, rInner, dynamicFill, physicsOffsetX, physicsOffsetY);
        }
        else if (state.wallpaperMode) {
            drawWallpaper(ctx, width, height, rOuter, rInner, dynamicFill, physicsOffsetX, physicsOffsetY);
        } else {
            drawSingleStar(ctx, width, height, rOuter, rInner, dynamicFill, physicsOffsetX, physicsOffsetY);
        }

        ctx.restore();
    }

    // V13 Post-Processing Filters
    applyFilters(ctx, canvas);
}



function drawSingleStar(ctx, w, h, rOuter, rInner, dynamicFill, offsetX = 0, offsetY = 0) {
    const cx = w / 2 + offsetX;
    const cy = h / 2 + offsetY;

    ctx.fillStyle = getFillStyle(ctx, cx, cy, rOuter, dynamicFill);

    // V8 Mouse Parallax
    if (state.parallaxEnabled) {
        const px = (state.mouseX / w - 0.5) * 30;
        const py = (state.mouseY / h - 0.5) * 30;
        ctx.translate(px, py);
    }

    ctx.save();
    ctx.translate(cx, cy);
    ctx.rotate(state.rotation);

    ctx.rotate(state.rotation);

    if (state.fractalMode) {
        renderRecursiveFractal(ctx, w, h, rOuter, rInner);
    } else {
        drawStarPath(ctx, state.spikes, rOuter, rInner, state.curve, state.twist);
        ctx.fill();
        if (state.lineWidth > 0) ctx.stroke();
    }

    ctx.restore();
}

function drawKaleidoscope(ctx, w, h, rOuter, rInner, dynamicFill, offsetX = 0, offsetY = 0) {
    const cx = w / 2;
    const cy = h / 2;
    const segs = state.segments;
    const angle = (Math.PI * 2) / segs;

    for (let i = 0; i < segs; i++) {
        ctx.save();
        ctx.translate(cx, cy);
        ctx.rotate(i * angle);
        ctx.translate(rOuter / 2, 0);
        ctx.rotate(state.rotation);

        const scale = 3 / segs;
        ctx.scale(scale, scale);

        ctx.fillStyle = getFillStyle(ctx, 0, 0, rOuter, dynamicFill);

        if (state.fractalMode) {
            renderRecursiveFractal(ctx, w, h, rOuter, rInner);
        } else {
            drawStarPath(ctx, state.spikes, rOuter, rInner, state.curve, state.twist);
            ctx.fill();
            if (state.lineWidth > 0) ctx.stroke();
        }

        ctx.restore();
    }

    // Center Star
    drawSingleStar(ctx, w, h, rOuter / 2, rInner / 2, dynamicFill);
}

function drawWallpaper(ctx, w, h, rOuter, rInner, dynamicFill, offsetX = 0, offsetY = 0) {
    const rows = state.rows;
    const cols = state.cols;
    const cellW = w / cols;
    const cellH = h / rows;

    for (let r = 0; r < rows; r++) {
        for (let c = 0; c < cols; c++) {
            const cx = (c * cellW) + (cellW / 2);
            const cy = (r * cellH) + (cellH / 2);

            ctx.fillStyle = getFillStyle(ctx, cx, cy, rOuter, dynamicFill);

            ctx.save();
            ctx.translate(cx, cy);
            ctx.rotate(state.rotation);

            if (state.fractalMode) {
                renderRecursiveFractal(ctx, w, h, rOuter, rInner);
            } else {
                drawStarPath(ctx, state.spikes, rOuter, rInner, state.curve, state.twist);
                ctx.fill();
                if (state.lineWidth > 0) ctx.stroke();
            }

            ctx.restore();
        }
    }
}

function getFillStyle(ctx, cx, cy, r, dynamicFill) {
    const color1 = dynamicFill || state.fillColor;
    const color2 = state.rainbowMode ? `hsl(${(Date.now() / 20 + 180) % 360}, 70%, 50%)` : state.fillColor2;

    if (state.useGradient) {
        const gradient = ctx.createRadialGradient(cx, cy, state.innerRadius / 4, cx, cy, r);
        gradient.addColorStop(0, color1);
        gradient.addColorStop(1, color2);
        return gradient;
    }
    return color1;
}
237 lines•7 KB
javascript
js/controls.js
Raw Download
Find: Go to:
/* V7 Controls Logic */
import { state } from './state.js';
import { exportPNG, toggleVideoRecording, recordGIF, exportSVG } from './export.js';
import { initAudio } from './audio.js';
import { savePattern } from './gallery.js';
import { THEMES, applyTheme } from './themes.js';
import { randomizeState } from './randomizer.js';
import { PRESETS, applyPreset } from './presets.js';
import { updateAnimations } from './animations.js';

export function initControls(canvas, ctx) {
    const controls = {
        spikes: document.getElementById('spikes'),
        outerRadius: document.getElementById('outerRadius'),
        innerRadius: document.getElementById('innerRadius'),
        curve: document.getElementById('curve'),
        twist: document.getElementById('twist'),
        lineWidth: document.getElementById('lineWidth'),
        glow: document.getElementById('glow'),
        jitter: document.getElementById('jitter'),
        speed: document.getElementById('speed'),

        wallpaperMode: document.getElementById('wallpaperMode'),
        cols: document.getElementById('cols'),
        rows: document.getElementById('rows'),

        kaleidoscopeMode: document.getElementById('kaleidoscopeMode'),
        segments: document.getElementById('segments'),

        audioMode: document.getElementById('audioMode'),

        fillColor: document.getElementById('fillColor'),
        fillColor2: document.getElementById('fillColor2'),
        useGradient: document.getElementById('useGradient'),
        strokeColor: document.getElementById('strokeColor'),
        bgColor: document.getElementById('bgColor'),

        // New Particles
        particlesEnabled: document.getElementById('particlesEnabled'),

        // V8 FX
        rainbowMode: document.getElementById('rainbowMode'),
        pulseEnabled: document.getElementById('pulseEnabled'),
        pulseEnabled: document.getElementById('pulseEnabled'),
        parallaxEnabled: document.getElementById('parallaxEnabled'),

        // V9
        fractalMode: document.getElementById('fractalMode'),
        fractalDepth: document.getElementById('fractalDepth'),

        // V11
        trailEnabled: document.getElementById('trailEnabled'),
        echoEnabled: document.getElementById('echoEnabled'),

        // V12
        gravityEnabled: document.getElementById('gravityEnabled'),
        orbitEnabled: document.getElementById('orbitEnabled'),
        chromaticAberration: document.getElementById('chromaticAberration'),
        holographicMode: document.getElementById('holographicMode'),

        // V13
        glitchEnabled: document.getElementById('glitchEnabled'),
        scanlinesEnabled: document.getElementById('scanlinesEnabled'),
        vignetteEnabled: document.getElementById('vignetteEnabled'),
        bloomEnabled: document.getElementById('bloomEnabled'),
        morphEnabled: document.getElementById('morphEnabled'),
        colorShiftEnabled: document.getElementById('colorShiftEnabled'),
        mandalaMode: document.getElementById('mandalaMode'),
        spiralMode: document.getElementById('spiralMode')
    };

    const displays = {
        spikes: document.getElementById('spikesVal'),
        outerRadius: document.getElementById('outerRadiusVal'),
        innerRadius: document.getElementById('innerRadiusVal'),
        curve: document.getElementById('curveVal'),
        twist: document.getElementById('twistVal'),
        lineWidth: document.getElementById('lineWidthVal'),
        glow: document.getElementById('glowVal'),
        jitter: document.getElementById('jitterVal'),
        speed: document.getElementById('speedVal'),
        cols: document.getElementById('colsVal'),
        rows: document.getElementById('rowsVal'),
        segments: document.getElementById('segmentsVal'),
        fractalDepth: document.getElementById('depthVal')
    };

    function updateState(key, value) {
        if (['useGradient', 'wallpaperMode', 'kaleidoscopeMode', 'audioMode', 'particlesEnabled', 'rainbowMode', 'pulseEnabled', 'parallaxEnabled', 'fractalMode', 'trailEnabled', 'echoEnabled', 'gravityEnabled', 'orbitEnabled', 'chromaticAberration', 'holographicMode', 'glitchEnabled', 'scanlinesEnabled', 'vignetteEnabled', 'bloomEnabled', 'morphEnabled', 'colorShiftEnabled', 'mandalaMode', 'spiralMode'].includes(key)) {
            state[key] = value;
        } else {
            state[key] = (key.includes('Color')) ? value : parseInt(value);
        }

        if (displays[key]) displays[key].textContent = state[key];

        if (key === 'audioMode' && value === true) initAudio();

        // Trigger draw if window._triggerDraw exists
        if (window._triggerDraw) window._triggerDraw();

        // Start loop if needed
        const needsLoop = state.speed > 0 || state.audioMode || state.particlesEnabled;
        if (needsLoop && window._triggerLoop) window._triggerLoop();
    }

    // Attach Listeners
    Object.keys(controls).forEach(key => {
        const input = controls[key];
        if (!input) return;

        const eventType = (input.type === 'checkbox' || input.type.includes('color')) ? 'input' : 'input';

        input.addEventListener(eventType, (e) => {
            const val = (input.type === 'checkbox') ? input.checked : input.value;
            updateState(key, val);
        });
    });

    // Buttons
    document.getElementById('exportBtn').addEventListener('click', () => exportPNG(canvas));
    document.getElementById('recordBtn').addEventListener('click', (e) => toggleVideoRecording(canvas, e.target));
    document.getElementById('recordGifBtn').addEventListener('click', (e) => recordGIF(canvas, e.target));
    document.getElementById('exportSvgBtn').addEventListener('click', () => exportSVG(canvas));

    // Gallery Save
    // Gallery Save (V10 - Auto Name)
    function triggerSave() {
        const name = `Pattern ${new Date().toLocaleString()}`;
        savePattern(name, canvas.toDataURL('image/png', 0.2));

        // Simple Toast Feedback (Console for now, or UI)
        const btn = document.getElementById('savePatternBtn');
        const originalText = btn.innerHTML;
        btn.innerHTML = '<i class="fas fa-check"></i> Saved!';
        setTimeout(() => btn.innerHTML = originalText, 1500);
    }
    document.getElementById('savePatternBtn').addEventListener('click', triggerSave);

    // Randomize (V10)
    function triggerRandom() {
        randomizeState(state);
        // Sync UI toggles/inputs
        Object.keys(controls).forEach(k => {
            if (controls[k]) {
                if (controls[k].type === 'checkbox') controls[k].checked = state[k];
                else controls[k].value = state[k];
                if (displays[k]) displays[k].textContent = state[k];
            }
        });
        if (window._triggerDraw) window._triggerDraw();
    }
    // Bind if button exists (we need to add it to HTML)
    const rndBtn = document.getElementById('randomizeBtn');
    if (rndBtn) rndBtn.addEventListener('click', triggerRandom);

    // Keyboard Shortcuts (V10)
    window.addEventListener('keydown', (e) => {
        // Ignore if typing in an input
        if (e.target.tagName === 'INPUT') return;

        switch (e.key.toLowerCase()) {
            case ' ': // Space: Toggle Animation
                state.speed = state.speed > 0 ? 0 : 2;
                if (controls.speed) controls.speed.value = state.speed;
                if (displays.speed) displays.speed.textContent = state.speed;
                if (state.speed > 0 && window._triggerLoop) window._triggerLoop();
                e.preventDefault();
                break;
            case 'r': // R: Randomize
                triggerRandom();
                break;
            case 's': // S: Save
                if (e.ctrlKey || e.metaKey) { // Ctrl+S usually saves page, let's override? 
                    e.preventDefault();
                    triggerSave();
                } else {
                    triggerSave();
                }
                break;
        }
    });

    // Listen for Load Event
    window.addEventListener('loadPattern', (e) => {
        const id = e.detail;
        // logic is handled in gallery.js loading to State, but we need to update UI controls
        // This is tricky. Reactivity usually handles this.
        // We need to sync Controls -> State.
        // Let's reload page? No.
        // Let's manually require a sync function.
        import('./gallery.js').then(({ loadPattern }) => {
            if (loadPattern(id)) {
                // Sync UI
                Object.keys(controls).forEach(k => {
                    if (controls[k]) {
                        if (controls[k].type === 'checkbox') controls[k].checked = state[k];
                        else controls[k].value = state[k];
                        if (displays[k]) displays[k].textContent = state[k];
                    }
                });
                if (window._triggerDraw) window._triggerDraw();
            }
        });
    });

    // Parallax Mouse Tracking (V8)
    const previewArea = document.getElementById('previewContainer');
    if (previewArea) {
        previewArea.addEventListener('mousemove', (e) => {
            if (!state.parallaxEnabled) return;

            const rect = previewArea.getBoundingClientRect();
            // Normalize -1 to 1
            const x = (e.clientX - rect.left) / rect.width;
            const y = (e.clientY - rect.top) / rect.height;

            state.mouseX = (x - 0.5) * 2;
            state.mouseY = (y - 0.5) * 2;

            if (window._triggerDraw) window._triggerDraw();
        });

        previewArea.addEventListener('mouseleave', () => {
            state.mouseX = 0;
            state.mouseY = 0;
            if (window._triggerDraw) window._triggerDraw();
        });
    }

    // Generate Themes (V9)
    const themeGrid = document.getElementById('themeGrid');
    if (themeGrid) {
        THEMES.forEach((t, i) => {
            const btn = document.createElement('div');
            btn.style.width = '30px';
            btn.style.height = '30px';
            btn.style.borderRadius = '50%';
            btn.style.background = `linear-gradient(135deg, ${t.fillColor}, ${t.fillColor2})`;
            btn.style.border = '2px solid rgba(255,255,255,0.2)';
            btn.style.cursor = 'pointer';
            btn.title = t.name;
            btn.onclick = () => applyTheme(i);
            themeGrid.appendChild(btn);
        });
    }

    // Listen for Theme Change to Sync UI
    window.addEventListener('themeChanged', (e) => {
        const t = e.detail;
        if (controls.fillColor) controls.fillColor.value = t.fillColor;
        if (controls.fillColor2) controls.fillColor2.value = t.fillColor2;
        if (controls.strokeColor) controls.strokeColor.value = t.strokeColor;
        if (controls.bgColor) controls.bgColor.value = t.bgColor;
        if (controls.glow) controls.glow.value = t.glow;
        if (displays.glow) displays.glow.textContent = t.glow;

        if (window._triggerDraw) window._triggerDraw();
    });

    // Generate Presets (V12)
    const presetGrid = document.getElementById('presetGrid');
    if (presetGrid) {
        PRESETS.forEach((p, i) => {
            const btn = document.createElement('button');
            btn.className = 'btn btn-outline';
            btn.style.width = '100%';
            btn.style.padding = '0.5rem';
            btn.style.fontSize = '0.85rem';
            btn.textContent = p.name;
            btn.onclick = () => {
                applyPreset(i);
                // Sync UI
                Object.keys(controls).forEach(k => {
                    if (controls[k] && state.hasOwnProperty(k)) {
                        if (controls[k].type === 'checkbox') controls[k].checked = state[k];
                        else if (controls[k].type === 'range' || controls[k].type === 'color') controls[k].value = state[k];
                        if (displays[k]) displays[k].textContent = state[k];
                    }
                });
                if (window._triggerDraw) window._triggerDraw();
            };
            presetGrid.appendChild(btn);
        });
    }
}
287 lines•12.2 KB
javascript
🚀 Support RSK World

Subscribe to our YouTube channel for latest tutorials & updates!



Click subscribe & support our work ❤️

About RSK World

Founded by Molla Samser, with Designer & Tester Rima Khatun, RSK World is your one-stop destination for free programming resources, source code, and development tools.

Founder: Molla Samser
Designer & Tester: Rima Khatun

Development

  • Game Development
  • Web Development
  • Mobile Development
  • AI Development
  • Development Tools

Legal

  • Terms & Conditions
  • Privacy Policy
  • Disclaimer

Contact Info

Nutanhat, Mongolkote
Purba Burdwan, West Bengal
India, 713147

+91 93305 39277

hello@rskworld.in
support@rskworld.in

© 2026 RSK World. All rights reserved.

Content used for educational purposes only. View Disclaimer