Category: mero.live

  • Moral of the story!!! — https://mero.live

    Follow huge communities where everything is already fixed, tested, and well maintained. 😄

    Honestly, Go + Alpine hasn’t been a bad experience — I’ve been drilling it nonstop for the last 26 days on a VPS. But DigitalOcean won’t even allow sending simple emails by default — most mail ports are blocked, and you have to go through paid or verified setups to get email working properly.

    Alpine or other JS setups also make simple uploads feel harder than they should be… really??? 😂

    What I learned:
    Sometimes spending 30 minutes on cheap shared hosting + WordPress is far better than spending 26 days debugging massive VPS setups.

    Long live WordPress.

    I’m never ever going to step outside the WordPress zone again. I’ve tried many times and always ended up with dumb!!!

    Code is poetry

  • three.js with mero.live

    <style>#media-3d-canvas {
           position: fixed;
           top: 0;
           left: 0;
           width: 100vw;
           height: 100vh;
           background-color: #000;
           z-index: 1; /* Make sure this is behind your Alpine UI */
       }
       #media-vault {
           display: none;
       }
       .page-container {
           position: relative;
           z-index: 2; /* Keeps Alpine loader/UI on top */
           pointer-events: none; /* Allows clicks to pass through to the 3D gallery */
       }
       .page-container * {
           pointer-events: auto; /* Re-enables clicking for UI elements */
       }</style>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.149.0/three.min.js"></script>
    <script>
       window.addEventListener('load', function() {
           console.log("Gallery: Waiting for Alpine...");
    
           let alpineCheck = setInterval(() => {
               const el = document.querySelector('[x-data]');
               if (window.Alpine && el) {
                   // Support both Alpine v2 and v3
                   const data = el.__x ? el.__x.data : (window.Alpine.$data ? window.Alpine.$data(el) : null);
    
                   if (data && data.vids && data.vids.length > 0) {
                       console.log("Gallery: Data found, starting 3D...");
                       clearInterval(alpineCheck);
                       init3DGallery(data);
                   }
               }
           }, 100);
    
           function init3DGallery(alpineData) {
               const container = document.getElementById('media-3d-canvas');
               const vault = document.getElementById('media-vault');
    
               let scene, camera, renderer, raycaster, mouse;
               let planes = [];
               let velocity = new THREE.Vector3(0, 0, 0);
               let targetVel = new THREE.Vector3(0, 0, 0);
               let autoVel = new THREE.Vector3(0, 0, -0.2);
    
               let isDragging = false, interactionStarted = false;
               let lastPointer = { x: 0, y: 0 };
               let mediaIndexCounter = 0;
    
               const isMobile = /Android|iPhone/i.test(navigator.userAgent);
               const ACTIVE_COUNT = isMobile ? 10 : 20;
               const TUNNEL_LENGTH = 1600;
               const SPREAD = 700;
    
               function init() {
                   scene = new THREE.Scene();
                   scene.background = new THREE.Color(0x000000);
                   scene.fog = new THREE.Fog(0x000000, 100, TUNNEL_LENGTH * 0.9);
    
                   camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 3000);
                   camera.position.z = 500;
    
                   renderer = new THREE.WebGLRenderer({ antialias: true });
                   renderer.setSize(window.innerWidth, window.innerHeight);
                   renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
                   container.appendChild(renderer.domElement);
    
                   raycaster = new THREE.Raycaster();
                   mouse = new THREE.Vector2();
    
                   for (let i = 0; i < ACTIVE_COUNT; i++) { createPlane(i); }
    
                   const startVideos = () => {
                       if (interactionStarted) return;
                       interactionStarted = true;
                       planes.forEach(p => { if(p.userData.video) p.userData.video.play().catch(()=>{}) });
                   };
    
                   container.addEventListener('mousedown', e => {
                       isDragging = true;
                       lastPointer.x = e.clientX;
                       lastPointer.y = e.clientY;
                       startVideos();
                   });
                   window.addEventListener('mouseup', () => isDragging = false);
                   window.addEventListener('mousemove', onMouseMove);
    
                   container.addEventListener('touchstart', e => {
                       isDragging = true;
                       lastPointer.x = e.touches[0].clientX;
                       lastPointer.y = e.touches[0].clientY;
                       startVideos();
                   }, {passive: false});
    
                   container.addEventListener('touchmove', e => {
                       if(!isDragging) return;
                       const dX = e.touches[0].clientX - lastPointer.x;
                       const dY = e.touches[0].clientY - lastPointer.y;
                       targetVel.x -= dX * 0.2; targetVel.y += dY * 0.2;
                       lastPointer.x = e.touches[0].clientX; lastPointer.y = e.touches[0].clientY;
                   }, {passive: false});
    
                   container.addEventListener('touchend', () => isDragging = false);
                   container.addEventListener('click', onSelect);
                   window.addEventListener('resize', onResize);
    
                   animate();
               }
    
               function createPlane(index) {
                   // Using BufferGeometry for compatibility with r149
                   const geo = new THREE.PlaneBufferGeometry(1, 1);
                   // Start with a grey color so we can see them even if video is loading
                   const mat = new THREE.MeshBasicMaterial({ color: 0x222222, side: THREE.DoubleSide });
                   const mesh = new THREE.Mesh(geo, mat);
                   const zPos = 500 - (index * (TUNNEL_LENGTH / ACTIVE_COUNT));
                   mesh.position.set((Math.random()-0.5)*SPREAD, (Math.random()-0.5)*SPREAD, zPos);
                   scene.add(mesh);
                   planes.push(mesh);
                   recyclePlane(mesh);
               }
    
               function recyclePlane(mesh) {
                   const vids = alpineData.vids;
                   const videoData = vids[mediaIndexCounter % vids.length];
                   const originalIndex = mediaIndexCounter % vids.length;
                   mediaIndexCounter++;
    
                   if (mesh.userData.video) {
                       mesh.userData.video.pause();
                       mesh.userData.video.src = "";
                       mesh.userData.video.remove();
                   }
    
                   const v = document.createElement('video');
    
                   // PATH LOGIC FIX:
                   // Converts "/thumbs/123.webp" to "/videos/123.mp4"
                   let videoSrc = videoData.thumb
                       .replace('/thumbs/', '/videos/')
                       .replace('.webp', '.mp4');
    
                   v.src = videoSrc;
                   v.muted = true;
                   v.loop = true;
                   v.playsInline = true;
                   v.crossOrigin = "anonymous";
                   vault.appendChild(v);
    
                   if (interactionStarted) v.play().catch(()=>{});
    
                   const tex = new THREE.VideoTexture(v);
                   mesh.material.map = tex;
                   mesh.material.color.set(0xffffff); // Set back to white once texture is assigned
                   mesh.userData.video = v;
                   mesh.userData.index = originalIndex;
                   mesh.userData.baseX = (Math.random() - 0.5) * SPREAD;
                   mesh.userData.baseY = (Math.random() - 0.5) * SPREAD;
    
                   const unit = window.innerWidth / (isMobile ? 2.5 : 5);
                   mesh.scale.set(unit * 0.56, unit, 1);
               }
    
               function animate() {
                   requestAnimationFrame(animate);
                   if (!isDragging) camera.position.add(autoVel);
    
                   velocity.lerp(targetVel, 0.1);
                   camera.position.add(velocity);
                   targetVel.multiplyScalar(0.9);
    
                   const camZ = camera.position.z;
                   planes.forEach(mesh => {
                       // Infinite Loop
                       if (mesh.position.z > camZ + 200) {
                           mesh.position.z -= TUNNEL_LENGTH;
                           recyclePlane(mesh);
                       } else if (mesh.position.z < camZ - (TUNNEL_LENGTH - 200)) {
                           mesh.position.z += TUNNEL_LENGTH;
                           recyclePlane(mesh);
                       }
    
                       // Autoplay Center logic
                       const distToCam = Math.abs(mesh.position.z - (camZ - 350));
                       if (distToCam < 120) {
                           if (mesh.userData.video?.paused && interactionStarted) mesh.userData.video.play().catch(()=>{});
                           // Scale up the center video
                           const scaleFactor = isMobile ? 1.8 : 1.5;
                           mesh.scale.lerp(new THREE.Vector3((window.innerWidth/4)*0.56*scaleFactor, (window.innerWidth/4)*scaleFactor, 1), 0.1);
                       } else {
                           if (!mesh.userData.video?.paused) mesh.userData.video?.pause();
                       }
                   });
                   renderer.render(scene, camera);
               }
    
               function onMouseMove(e) {
                   if (!isDragging) return;
                   targetVel.x -= (e.clientX - lastPointer.x) * 0.1;
                   targetVel.y += (e.clientY - lastPointer.y) * 0.1;
                   lastPointer.x = e.clientX; lastPointer.y = e.clientY;
               }
    
               function onSelect(e) {
                   mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
                   mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
                   raycaster.setFromCamera(mouse, camera);
                   const hits = raycaster.intersectObjects(planes);
                   if (hits.length > 0) {
                       const idx = hits[0].object.userData.index;
                       // Calls your Alpine openVideo function
                       if(alpineData.openVideo) alpineData.openVideo(idx);
                   }
               }
    
               function onResize() {
                   camera.aspect = window.innerWidth / window.innerHeight;
                   camera.updateProjectionMatrix();
                   renderer.setSize(window.innerWidth, window.innerHeight);
               }
    
               init();
           }
       });
       </script>
  • 📢 Why Advertise on Mero.live?

    🎯 Real attention, not fake views

    Your ads are shown to real active users watching real content.


    ⚙️ How Ads Work

    • You upload a video ad
    • You set budget and targeting
    • Your ad is shown inside videos
    • Only real watch time counts
    • You pay for valid attention only

    📍 Smart Targeting

    Show your ads to the right people:

    • Location-based targeting — reach users near you
    • Time-based targeting (morning / evening / weekend)
    • Interest tags (food, shop, service, etc.)
    • Active users only

    ⏱️ Attention-Based Delivery

    We don’t sell random impressions.

    Ads are shown during real attention moments

    This means:

    • higher engagement
    • better conversion
    • less wasted budget

    💰 Pay Only for Value

    You are not paying for empty views.

    You pay for:

    • Valid watch time
    • Real user attention
    • Targeted delivery

    📊 What You Get

    • Real users watching your ads
    • Local reach (nearby customers)
    • Time-based exposure (peak hours)
    • Real-time performance tracking
    • Optional Q&A with users
    • Optional Add-to-Cart orders checkout system

    🧠 Simple Summary

    Mero.live helps you reach real active users at the right time, not random audiences. You pay for attention, not noise.


  • How You Earn on Mero.live

    🎬 Simple idea

    You upload videos. Ads are shown inside your videos. You earn from attention.


    📢 How Ads Work

    • Ads are automatically placed inside videos
    • Ads are shown in a fair rotation system
    • Every active creator gets equal opportunity
    • No favoritism. No popularity boost.

    ⚖️ Fair System

    We do NOT rank creators by views or popularity.

    Instead:

    All active videos are shown in equal rotation over time

    This means:

    • Everyone gets a fair chance
    • Earnings are based on real ad views
    • No hidden algorithm bias

    💰 How You Earn

    You earn when:

    • An ad is shown in your video
    • The user watches it properly (valid view)

    Your earnings come from:

    Total ads shown inside your videos


    🚀 Simple Example

    • Your video is in rotation
    • Ads appear during playback
    • Every valid ad view adds earnings to your wallet

    More active platform usage = more earning chances


    ⚠️ Important Rules

    • No fake views
    • No spam uploads
    • No manipulation of watch time
    • Only real engagement is counted

    🧠 Summary

    Mero.live shows ads fairly across all active creators. You earn based on real ad attention, not popularity or followers.

  • mero.live login start page


    Mero.live

    LOGIN TO START

    [ LOGIN ]

    [ BECOME PARTNER ]
    Upload short videos. Earn from ads.
    No followers. No approval. No waiting.

    Earn 60% when ads run on your videos.

    [ START ADVERTISING ]
    Put your ad in real attention moments.
    Not random views. Not fake traffic.

    Reach active nearby users in real time


    ⚡ Google login required

  • Protected: mero.live ads manager

    This content is password-protected. To view it, please enter the password below.

  • Protected: mero.live dashboard partners

    This content is password-protected. To view it, please enter the password below.

  • mero.live update

    We just supercharged the app with CDN-level performance and smart data saving! Here is what’s new:

    • Smart Data Detection: The app now detects if you are on mobile data. It automatically switches to 1-second “Snapshot” mode for lightning-fast uploads that won’t eat your data plan.
    • Predictive Preloading: We implemented “Look-Ahead” logic. While you watch one video, the next one is already downloading in the background. Result: 0ms lag between clips.
    • CDN-Style Caching: We added aggressive 1-year browser caching. Once you watch a video, it stays on your phone’s disk for instant replay—no redownloading required.
    • Snappy Playback: We tuned our FFmpeg engine to insert frequent keyframes, ensuring videos start playing the exact millisecond they appear on screen.
  • Protected: mero.live

    This content is password-protected. To view it, please enter the password below.