OpenGuessr Legit Cheat

Undetectable | Press Tab to open the settings menu

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name    OpenGuessr Legit Cheat
// @namespace https://greasyfork.org/en/users/1588266-woggieboost
// @version    2.0
// @description    Undetectable | Press Tab to open the settings menu
// @author    woggieboost
// @license    MIT
// @match    *://*.openguessr.com/*
// @grant    GM_setValue
// @grant    GM_getValue
// @grant    GM_xmlhttpRequest
// @connect    discord.com
// @connect    nominatim.openstreetmap.org
// @icon    https://www.google.com/s2/favicons?sz=32&domain=openguessr.com
// ==/UserScript==

(function () {
    'use strict';

    // ========== Common Config ==========
    const DEFAULT_HOTKEYS = {
        openPanel: 'tab',
        sendToDiscord: 'q',
        notify: 'g',
        toggleMarker: 'x',
        toggleInfo: 'v',
    };

    const DEFAULT_TOGGLES = {
        sendToDiscord: true,
        autoSend: false,
        notify: true,
        autoNotify: false,
        toggleMarker: true,
        toggleInfo: true,
    };

    // ========== Global State ==========
    let state = {
        notificationPermission: Notification.permission,
        streetView: null,
        gameMap: null,
        mapMarker: null,
        currentAddress: null,
        isInfoDisplayed: false,
        lastCoord: null,
        originalNickname: null,
        originalFlag: null,
        logoElement: null,
        hotkeys: GM_getValue('hotkeys', DEFAULT_HOTKEYS),
        featureToggles: GM_getValue('featureToggles', DEFAULT_TOGGLES),
    };

    // Initialize missing hotkeys
    if (!state.hotkeys.openPanel) {
        state.hotkeys.openPanel = 'tab';
        GM_setValue('hotkeys', state.hotkeys);
    }

    // Initialize missing toggles
    if (state.featureToggles.autoSend === undefined) {
        state.featureToggles.autoSend = false;
        state.featureToggles.autoNotify = false;
        GM_setValue('featureToggles', state.featureToggles);
    }

    // ========== Utility Functions ==========
    function saveHotkeys() {
        GM_setValue('hotkeys', state.hotkeys);
    }

    function saveFeatureToggles() {
        GM_setValue('featureToggles', state.featureToggles);
    }

    function getMainDomain() {
        const parts = window.location.hostname.split(".");
        if (parts.length > 2) {
            return parts.slice(-2).join(".");
        }
        return window.location.hostname;
    }

    function requestNotificationPermission() {
        if (state.notificationPermission === 'default') {
            Notification.requestPermission().then(permission => {
                state.notificationPermission = permission;
            });
        }
    }

    function sendNotification(title, body) {
        if (state.notificationPermission === 'granted') {
            new Notification(title, {
                body,
                icon: `https://www.google.com/s2/favicons?sz=32&domain=${getMainDomain()}`
            });
        }
    }

    function throttle(fn, wait) {
        let lastTime = 0;
        let pendingPromise = null;

        return function (...args) {
            const now = Date.now();
            if (now - lastTime >= wait) {
                lastTime = now;
                pendingPromise = Promise.resolve(fn.apply(this, args));
                return pendingPromise;
            }
            return pendingPromise;
        };
    }

    function debounce(fn, wait) {
        let timeout;
        return function (...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => fn.apply(this, args), wait);
        };
    }

    // ========== Nominatim Service ==========
    function _getAddress(lat, lng) {
        if (state.lastCoord && state.lastCoord === [lat, lng]) {
            return Promise.resolve(state.currentAddress);
        }

        return new Promise((resolve, reject) => {
            const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&accept-language=en`;
            GM_xmlhttpRequest({
                method: 'GET',
                url,
                headers: { 'Accept': 'application/json' },
                onload: res => {
                    try {
                        resolve(JSON.parse(res.responseText));
                    } catch (err) {
                        reject(err);
                    }
                },
                onerror: err => reject(err)
            });
        });
    }

    const getAddress = throttle(_getAddress, 1000);

    // ========== Address Formatting ==========
    function formatAddress(address) {
        if (!address || !address.address) return null;

        const a = address.address;
        const parts = [
            a.country,
            a.state || a.province || a.region || a.county || a.prefecture,
            a.city || a.town || a.village,
            a.road || a.street,
        ];

        return parts.filter(Boolean).join(', ');
    }

    // ========== Tile URL Generation ==========
    function lonToTile(lng, zoom) {
        return Math.floor((lng + 180) / 360 * Math.pow(2, zoom));
    }

    function latToTile(lat, zoom) {
        return Math.floor(
            (1 - Math.log(Math.tan(lat * Math.PI / 180) + 1 / Math.cos(lat * Math.PI / 180)) / Math.PI) / 2
            * Math.pow(2, zoom)
        );
    }

    function buildTileUrl(lat, lng) {
        const zoom = 6;
        const tileX = lonToTile(lng, zoom);
        const tileY = latToTile(lat, zoom);
        return `https://mapsresources-pa.googleapis.com/v1/tiles?map_id=61449c20e7fc278b&version=sdk-15797339025669136861&pb=!1m5!1m4!1i${zoom}!2i${tileX}!3i${tileY}!4i256!2m3!1e0!2sm!3i773537392!3m13!2sen!3sUS!5e18!12m5!1e68!2m2!1sset!2sRoadmap!4e2!12m3!1e37!2m1!1ssmartmaps!4e0!5m2!1e3!5f2!23i46991212!23i47054750!23i47083502!23i56565656!26m2!1e2!1e3`;
    }

    // ========== Discord Integration ==========
    function createEmbed() {
        const { lat, lng } = getCoordinates();
        const query = `${lat},${lng}`;
        const formattedAddr = formatAddress(state.currentAddress) || getLocationDescription();

        return {
            title: '✅ Location Tracked',
            description: `### [${formattedAddr}](https://maps.google.com/?q=${query}&ll=${query}&z=5)`,
            color: 516235,
            image: {
                url: buildTileUrl(lat, lng)
            }
        };
    }

    function sendToDiscord(embed) {
        let webhookUrl = GM_getValue('discordWebhookUrl');
        if (!webhookUrl) {
            webhookUrl = prompt('Discord Webhook:', '');
            if (webhookUrl) {
                GM_setValue('discordWebhookUrl', webhookUrl);
            } else {
                alert('You must provide a Discord Webhook URL to continue.');
                return;
            }
        }

        const payload = JSON.stringify({
            embeds: [embed],
            username: 'OpenGuessr Legit Cheat',
            avatar_url: `https://www.google.com/s2/favicons?sz=32&domain=${getMainDomain()}`
        });

        GM_xmlhttpRequest({
            method: 'POST',
            url: webhookUrl,
            headers: { 'Content-Type': 'application/json' },
            data: payload,
            onload: res => {
                if (res.status !== 204) {
                    console.error('Discord error:', res);
                }
            },
            onerror: err => {
                console.error('Request failed:', err);
            }
        });
    }



    // Coordinate getter
    function getCoordinates() {
        try {

            const iframe = document.querySelector('#PanoramaIframe') ||
                  document.querySelector('iframe[src*="location"]') ||
                  document.querySelector('.iframeWithStreetView');

            if (iframe && (iframe.src || iframe.data)) {
                const loc = new URL(iframe.src || iframe.data).searchParams.get('location');
                if (loc) {
                    const [lat, lng] = loc.split(',').map(Number);
                    return { lat, lng };
                }
            }
        } catch (e) {
            console.error('Failed to extract coordinates:', e);
        }
        return { lat: undefined, lng: undefined };
    }


    // Nickname getter/setter
    function getNicknameElement() {
        const elements = document.querySelectorAll('.player-name');
        return elements[1] || null;
    }

    function setNickname(text) {
        const el = getNicknameElement();
        if (el) {
            el.textContent = text || getLocationDescription();
        }
    }

    // Flag getter/setter
    function getFlagElement() {
        let flagEl = document.querySelectorAll('.player-name-wrapper .player-name img')[1];
        if (!flagEl) {
            const container = getNicknameElement();
            if (container) {
                flagEl = document.createElement('img');
                Object.assign(flagEl, { src: 'https://flagcdn.com/w80/us.png' });
                Object.assign(flagEl.style, {
                    display: 'inline-block',
                    width: '1.5em',
                    height: '1em',
                    marginRight: '0.4em',
                    verticalAlign: 'middle',
                    flexShrink: '0',
                    objectFit: 'cover',
                    borderRadius: '2px'
                });
                container.appendChild(flagEl);
            }
        }
        return flagEl;
    }

    function setFlag(countryCode) {
        const el = getFlagElement();
        if (el && countryCode) {
            el.src = `https://flagcdn.com/48x36/${countryCode.toLowerCase()}.png`;
        }
    }

    // Logo element creator for OpenGuessr/WorldGuessr
    function createLogoElement() {
        const logoContainer = document.querySelector('.logo');
        if (logoContainer) {
            const imgEl = logoContainer.querySelector('img');
            let imgClass = '';
            if (imgEl) {
                imgClass = imgEl.className;
                imgEl.remove();
            }

            const newEl = document.createElement('div');
            newEl.className = imgClass;
            Object.assign(newEl.style, {
                width: '480px',
                opacity: '0',
                fontSize: '20px',
                color: '#fff',
                fontWeight: 'bold',
                textShadow: '#CC302E 2px 0px 0px, #CC302E 1.75517px 0.958851px 0px, #CC302E 1.0806px 1.68294px 0px, #CC302E 0.141474px 1.99499px 0px, #CC302E -0.832294px 1.81859px 0px, #CC302E -1.60229px 1.19694px 0px, #CC302E -1.97998px 0.28224px 0px, #CC302E -1.87291px -0.701566px 0px, #CC302E -1.30729px -1.5136px 0px, #CC302E -0.421592px -1.95506px 0px, #CC302E 0.567324px -1.91785px 0px, #CC302E 1.41734px -1.41108px 0px, #CC302E 1.92034px -0.558831px 0px'
            });
            logoContainer.appendChild(newEl);
            return newEl;
        }


        return null;
    }

    // ========== Address Display ==========
    async function updateAddressDisplay() {
        if (!state.logoElement) {
            state.logoElement = createLogoElement();
        }
        if (state.logoElement) {
            if (state.isInfoDisplayed) {
                state.logoElement.style.opacity = 1;
                state.logoElement.textContent = formatAddress(state.currentAddress);
            }
            else state.logoElement.style.opacity = 0;
        }
    }

    // ========== Map Marker Management ==========
    function spawnRipple(lat, lng) {
        if (state.gameMap) {
            // Leaflet
            const rippleIcon = L.divIcon({
                className: '',
                html: '<div class="ripple-effect"></div>',
                iconSize: [80, 80],
                iconAnchor: [40, 40]
            });

            const rippleMarker = L.marker([lat, lng], {
                icon: rippleIcon,
                interactive: false
            }).addTo(state.gameMap);

            setTimeout(() => {
                state.gameMap.removeLayer(rippleMarker);
            }, 2000);
        }
    }

    function toggleMapMarker() {
        if (!state.gameMap) return;

        const { lat, lng } = getCoordinates();
        if (lat === undefined || lng === undefined) return;

        // Leaflet
        if (state.mapMarker) {
            state.gameMap.removeLayer(state.mapMarker);
            state.mapMarker = null;
        } else {
            const customIcon = L.icon({
                iconUrl: 'https://openguessr.com/img/pins/result_pin.png',
                iconSize: [35, 35],
                iconAnchor: [17.5, 35],
            });
            state.mapMarker = L.marker([lat, lng], {
                icon: customIcon
            }).addTo(state.gameMap);
        }

        spawnRipple(lat, lng);
        setTimeout(() => spawnRipple(lat, lng), 300);
        setTimeout(() => spawnRipple(lat, lng), 600);
    }

    // ========== Settings Panel ==========
    function createSettingsPanel() {
        const panel = document.createElement('div');
        panel.id = 'cgx-settings-panel';
        panel.style.cssText = `
            position: fixed;
            top: 30%;
            left: 40%;
            width: 300px;
            background: rgba(25, 25, 25, 0.92);
            color: #fff;
            padding: 18px;
            border-radius: 12px;
            z-index: 999999;
            font-size: 14px;
            backdrop-filter: blur(10px);
            border: 1px solid rgba(255,255,255,0.08);
            box-shadow: 0 8px 20px rgba(0,0,0,0.35);
            animation: cgxFadeIn 0.18s ease-out;
        `;

        panel.innerHTML = `
            <style>
                @keyframes cgxFadeIn {
                    from { opacity: 0; transform: translateY(-6px); }
                    to { opacity: 1; transform: translateY(0); }
                }

                .cgx-input {
                    width: 50px;
                    text-align: center;
                    padding: 4px 6px;
                    border-radius: 6px;
                    border: 1px solid rgba(255,255,255,0.15);
                    background: rgba(255,255,255,0.08);
                    color: #fff;
                    outline: none;
                    transition: 0.15s;
                }
                .cgx-input:focus {
                    border-color: #4caf50;
                    background: rgba(255,255,255,0.15);
                }

                .cgx-btn {
                    width: 100%;
                    padding: 8px;
                    margin-top: 10px;
                    border-radius: 8px;
                    border: none;
                    cursor: pointer;
                    font-size: 14px;
                    transition: 0.15s;
                }
                .cgx-save-btn { background: #4caf50; color: white; }
                .cgx-reset-btn { background: #2196f3; color: white; }
                .cgx-reset-btn:hover { background: #42a5f5; }
                .cgx-btn:disabled {
                    background: #c0c0c0 !important;
                    cursor: default;
                    opacity: 0.9;
                }

                .cgx-close-btn {
                    position: absolute;
                    top: 8px;
                    right: 10px;
                    font-size: 18px;
                    color: #ccc;
                    cursor: pointer;
                    transition: 0.15s;
                    user-select: none;
                }
                .cgx-close-btn:hover {
                    color: #cd312f;
                    transform: scale(1.15);
                }
                .cgx-toggle {
                    width: 36px;
                    height: 18px;
                    border-radius: 20px;
                    background: rgba(255,255,255,0.2);
                    position: relative;
                    cursor: pointer;
                    transition: 0.2s;
                }
                .cgx-toggle::after {
                    content: "";
                    position: absolute;
                    width: 14px;
                    height: 14px;
                    top: 2px;
                    left: 2px;
                    border-radius: 50%;
                    background: #fff;
                    transition: 0.2s;
                }

                .cgx-toggle.active {
                    background: #4caf50;
                    box-shadow: 0 0 6px rgba(76,175,80,0.6);
                }

                .cgx-toggle.active::after {
                    left: 20px;
                }
            </style>

            <div class="cgx-close-btn">✕</div>

            <div style="font-size:17px; text-align:center; font-weight:bold; margin-bottom:12px;">
                Hotkeys Settings
            </div>

            ${Object.keys(DEFAULT_TOGGLES).map(key => `
                <div style="margin-bottom:10px; display:flex; align-items:center; justify-content:space-between;">
                    <div style="display:flex; align-items:center; gap:8px;">
                        ${key !== 'openPanel' ? `<div class="cgx-toggle ${state.featureToggles[key] ? 'active' : ''}" data-toggle="${key}"></div>` : `<div style="width:36px;"></div>`}
                        <span>${key}</span>
                    </div>
                    ${['autoSend', 'autoNotify'].includes(key) ? '' : `<input class="cgx-input" type="text" data-key="${key}" value="${state.hotkeys[key] || ''}">`}
                </div>
            `).join('')}

            <button id="cgx-save-hotkeys" class="cgx-btn cgx-save-btn">Save</button>
            <button id="cgx-reset-hotkeys" class="cgx-btn cgx-reset-btn">Reset</button>
        `;

        document.body.appendChild(panel);

        // Close button
        panel.querySelector('.cgx-close-btn').onclick = () => {
            panel.style.display = 'none';
        };

        // Toggles
        panel.querySelectorAll('.cgx-toggle').forEach(toggle => {
            toggle.onclick = () => {
                const key = toggle.dataset.toggle;
                state.featureToggles[key] = !state.featureToggles[key];
                toggle.classList.toggle('active');
                saveFeatureToggles();
            };
        });

        // Save button
        const saveBtn = document.getElementById('cgx-save-hotkeys');
        saveBtn.onclick = () => {
            panel.querySelectorAll('.cgx-input').forEach(input => {
                const key = input.dataset.key;
                const val = input.value.trim().toLowerCase();
                if (val) state.hotkeys[key] = val;
            });

            saveHotkeys();
            saveFeatureToggles();

            saveBtn.textContent = 'Saved';
            saveBtn.disabled = true;

            setTimeout(() => {
                saveBtn.textContent = 'Save';
                saveBtn.disabled = false;
            }, 1200);
        };

        // Reset button
        const resetBtn = document.getElementById('cgx-reset-hotkeys');
        resetBtn.onclick = () => {
            state.hotkeys = { ...DEFAULT_HOTKEYS };
            saveHotkeys();

            panel.querySelectorAll('.cgx-input').forEach(input => {
                input.value = state.hotkeys[input.dataset.key];
            });

            resetBtn.textContent = 'Reset';
            resetBtn.disabled = true;
        };

        // Key input handling
        panel.querySelectorAll('.cgx-input').forEach(input => {
            input.addEventListener('keydown', e => {
                e.preventDefault();

                let key = e.key.toLowerCase();

                if (['shift', 'control', 'alt', 'meta'].includes(key)) return;

                if (key === ' ') key = 'space';

                input.value = key;
                resetBtn.disabled = false;
            });
        });
    }

    function extractStreetView() {
        try {
            const container = document.querySelector('div[data-qa="panorama"]');
            if (!container) return;

            const fiberKey = Object.keys(container).find(k => k.startsWith('__reactFiber'));
            if (!fiberKey) return;

            const fiberNode = container[fiberKey];
            state.streetView =
                fiberNode.return.return.return.sibling.memoizedProps.panorama ||
                fiberNode.return.updateQueue.lastEffect.next.next.next.next.next.next.next.next.next.next.next.deps[0];
        } catch (err) {
            state.streetView = null;
        }
    }

    function extractMapInstance() {
        try {
            const mapElement = document.querySelector("[class*='guess-map_canvas']") || document.querySelector('.leaflet-container');
            if (!mapElement) return;

            const fiberKey = Object.keys(mapElement).find(k => k.startsWith('__reactFiber$'));
            if (!fiberKey) return;

            const fiberNode = mapElement[fiberKey];
            state.gameMap =
                fiberNode?.return?.memoizedProps?.map ||
                fiberNode?.return?.updateQueue?.lastEffect?.deps?.[0] ||
                fiberNode?.child?.memoizedProps?.value?.map;
        } catch (err) {
            state.gameMap = null;
        }
    }

    // ========== Keyboard Handler ==========
    async function handleKeyDown(e) {
        if (
            e.target.tagName === 'TEXTAREA' ||
            e.target.tagName === 'INPUT' ||
            e.target.isContentEditable
        ) return;

        const key = e.key.toLowerCase();
        const isHotkey =
              key === state.hotkeys.sendToDiscord ||
              key === state.hotkeys.toggleMarker ||
              key === state.hotkeys.toggleInfo ||
              key === state.hotkeys.notify ||
              key === state.hotkeys.openPanel;

        if (!isHotkey) return;

        if (key === state.hotkeys.openPanel) {
            const panel = document.getElementById('cgx-settings-panel');
            if (panel) {
                panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
            } else {
                createSettingsPanel();
            }
        }

        if (key === state.hotkeys.sendToDiscord && state.featureToggles.sendToDiscord) {
            sendToDiscord(createEmbed());
        }

        if (key === state.hotkeys.toggleMarker && state.featureToggles.toggleMarker) {
            if(!state.gameMap) extractMapInstance();
            toggleMapMarker();
        }

        if (key === state.hotkeys.toggleInfo && state.featureToggles.toggleInfo) {
            state.isInfoDisplayed = !state.isInfoDisplayed;
            updateAddressDisplay();
        }

        if (key === state.hotkeys.notify && state.featureToggles.notify) {
            requestNotificationPermission();
            sendNotification(
                'OpenGuessr Legit Cheat',
                formatAddress(state.currentAddress) || getLocationDescription()
            );
        }

        e.stopImmediatePropagation();
        e.stopPropagation();
    }

    document.addEventListener('keydown', handleKeyDown, true);

    // Prevent focus on iframe
    setInterval(() => {
        if (document.activeElement instanceof HTMLIFrameElement || document.activeElement instanceof Object) {
            window.focus();
            document.body.focus();
        }
    }, 200);

    // Monitor coordinate changes
    const coordObserver = new MutationObserver(() => {
        const streetViewContainer = document.getElementById('panorama-iframe') ||
              document.getElementById('streetview') ||
              document.querySelector('iframe[src*="location"]') ||
              document.querySelector('.iframeWithStreetView');
        if (streetViewContainer) {
            const intervalId = setInterval(async () => {
                const { lat, lng } = getCoordinates();
                if (lat && lng) {
                    if (state.lastCoord != [lat, lng]) {
                        state.lastCoord = [lat, lng];
                        state.currentAddress = await getAddress(lat, lng);
                        updateAddressDisplay();

                        if (state.mapMarker) {
                            state.mapMarker.setLatLng([lat, lng]);
                        }
                    }
                }
            }, 500);
            coordObserver.disconnect();
        }
    });

    coordObserver.observe(document.body, { childList: true, subtree: true });

    // Initialize Leaflet map
    const mapObserver = new MutationObserver(() => {
        try {
            if (L && L.map) {
                const originalSetView = L.Map.prototype.setView;
                L.Map.prototype.setView = function (...args) {
                    state.gameMap = this;
                    return originalSetView.apply(this, args);
                };
                mapObserver.disconnect();
            }
        } catch (err) {
        }
    });

    mapObserver.observe(document.body, { childList: true, subtree: true });


    // ========== Styles ==========
    const style = document.createElement('style');
    style.innerHTML = `
        .gameplayAdArea, .venatus-ad, #worldguessr_gameui_ad, #worldguessr_home_ad {
            display: none !important;
            visibility: hidden !important;
            opacity: 0 !important;
        }
        .gmap-ripple {
            position: absolute;
            width: 80px;
            height: 80px;
            pointer-events: none;
        }

        .gmap-ripple::before,
        .gmap-ripple::after {
            content: "";
            position: absolute;
            left: 0%;
            top: 0%;
            width: 80px;
            height: 80px;
            border-radius: 50%;
            transform: translate(-50%, -50%) scale(0.6);
            background: radial-gradient(
                circle,
                rgba(255, 80, 80, 0.6) 0%,
                rgba(255, 80, 80, 0.45) 40%,
                rgba(255, 80, 80, 0.3) 70%,
                transparent 100%
            );
        }

        .gmap-ripple::before {
            animation: gmapRipple 2s ease-out;
        }

        .gmap-ripple::after {
            animation: gmapRipple 2s ease-out 0.4s;
        }

        .ripple-effect {
            position: absolute;
            width: 80px;
            height: 80px;
        }

        .ripple-effect::before,
        .ripple-effect::after {
            content: "";
            position: absolute;
            left: 50%;
            top: 50%;
            width: 80px;
            height: 80px;
            border-radius: 50%;
            background: radial-gradient(
                circle,
                rgba(255, 60, 60, 0.6) 0%,
                rgba(255, 60, 60, 0.45) 35%,
                rgba(255, 60, 60, 0.3) 65%,
                transparent 100%
            );
            transform: translate(-50%, -50%) scale(1);
        }

        .ripple-effect::before {
            animation: ripple 2s ease-out;
        }

        .ripple-effect::after {
            animation: ripple 2s ease-out 0.4s;
        }

        @keyframes gmapRipple {
            0% {
                transform: translate(-50%, -50%) scale(0.8);
                opacity: 0.7;
            }
            100% {
                transform: translate(-50%, -50%) scale(8);
                opacity: 0;
            }
        }

        @keyframes ripple {
            0% {
                transform: translate(-50%, -50%) scale(0.8);
                opacity: 0.6;
            }
            100% {
                transform: translate(-50%, -50%) scale(8);
                opacity: 0;
            }
        }
    `;
    document.head.appendChild(style);

})();