🎮ArcadeLab

AgroTech Rush

by StormGecko10
642 lines21.2 KB
▶ Play
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>AgroTech Rush</title>
<style>
  :root{
    --bg1:#0b2e13;
    --bg2:#12421c;
    --panel:#1c5028;
    --panel-dark:#0e3016;
    --gold:#f4c542;
    --gold-dark:#c98f1f;
    --cream:#f4ecd8;
    --danger:#e0503a;
    --sky:#2ea7c9;
    --text:#f4ecd8;
    font-family: 'Courier New', 'Consolas', monospace;
  }
  *{box-sizing:border-box; -webkit-tap-highlight-color:transparent; user-select:none;}
  html,body{
    margin:0; padding:0; width:100%; height:100%;
    background: radial-gradient(ellipse at top, var(--bg2), var(--bg1) 70%);
    overflow:hidden; color:var(--text);
    touch-action:none;
  }
  #game{
    position:fixed; inset:0; display:flex; flex-direction:column;
  }
  #topbar{
    display:flex; align-items:center; justify-content:space-between;
    padding:8px 12px; background:var(--panel-dark);
    border-bottom:4px solid var(--gold-dark);
    font-weight:bold; font-size:clamp(12px,2.6vw,18px);
    flex-wrap:wrap; gap:4px 10px; z-index:5;
  }
  #topbar .stat{display:flex; align-items:center; gap:4px;}
  #hearts{letter-spacing:2px;}
  #comboWrap{color:var(--gold); min-width:70px; text-align:center;}
  #canvasWrap{position:relative; flex:1; min-height:0;}
  canvas{display:block; width:100%; height:100%;}
  #bins{
    display:flex; background:var(--panel-dark);
    border-top:4px solid var(--gold-dark);
    padding:6px; gap:6px; z-index:5;
  }
  .bin{
    flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center;
    background:var(--panel); border:3px solid var(--gold-dark); border-radius:10px;
    padding:8px 2px; cursor:pointer; color:var(--cream);
    font-size:clamp(18px,5.5vw,30px); line-height:1.1;
    transition:transform .06s, background .1s;
  }
  .bin small{font-size:clamp(8px,2vw,11px); letter-spacing:.5px;}
  .bin:active, .bin.pressed{transform:scale(.9); background:var(--gold-dark);}
  .bin.flash-good{background:#3f9142 !important;}
  .bin.flash-bad{background:var(--danger) !important;}

  .overlay{
    position:absolute; inset:0; z-index:20;
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    background:rgba(6,26,10,.92); text-align:center; padding:24px; gap:16px;
  }
  .hidden{display:none !important;}
  h1{
    color:var(--gold); font-size:clamp(28px,8vw,54px); margin:0;
    text-shadow:3px 3px 0 var(--gold-dark), 0 0 20px rgba(244,197,66,.5);
    letter-spacing:2px;
  }
  .subtitle{max-width:480px; font-size:clamp(13px,3.4vw,16px); line-height:1.5; color:var(--cream);}
  .legend{display:flex; flex-wrap:wrap; gap:10px; justify-content:center; max-width:520px;}
  .legend div{
    background:var(--panel); border:2px solid var(--gold-dark); border-radius:8px;
    padding:6px 10px; font-size:clamp(11px,2.8vw,14px);
  }
  button.big{
    font-family:inherit; font-weight:bold; font-size:clamp(16px,4.5vw,22px);
    padding:14px 34px; border-radius:12px; border:3px solid var(--gold-dark);
    background:linear-gradient(180deg,var(--gold),var(--gold-dark)); color:#1c1300;
    cursor:pointer; box-shadow:0 6px 0 #7a5a10; letter-spacing:1px;
  }
  button.big:active{transform:translateY(4px); box-shadow:0 2px 0 #7a5a10;}
  button.ghost{
    font-family:inherit; font-weight:bold; font-size:clamp(13px,3.4vw,16px);
    padding:10px 22px; border-radius:10px; border:2px solid var(--gold);
    background:transparent; color:var(--gold); cursor:pointer;
  }
  #factCard{
    background:var(--panel); border:3px solid var(--gold);
    border-radius:14px; padding:20px; max-width:480px;
  }
  #factCard .tag{color:var(--gold); font-weight:bold; letter-spacing:2px; font-size:13px;}
  #factCard p{font-size:clamp(14px,3.6vw,18px); line-height:1.5; margin:10px 0 0;}
  .score-big{font-size:clamp(30px,9vw,56px); color:var(--gold); font-weight:bold; text-shadow:2px 2px 0 var(--gold-dark);}
  .best{font-size:clamp(12px,3.2vw,15px); color:var(--sky);}
  #levelBadge{
    position:absolute; top:10px; left:50%; transform:translateX(-50%);
    background:var(--gold); color:#1c1300; font-weight:bold; padding:4px 14px;
    border-radius:20px; font-size:clamp(11px,3vw,14px); z-index:8; opacity:.92;
  }
</style>
</head>
<body>
<div id="game">

  <div id="topbar">
    <div class="stat">🏆 <span id="scoreVal">0</span></div>
    <div id="comboWrap">✨ x<span id="comboVal">1.0</span></div>
    <div class="stat" id="hearts">❤️❤️❤️</div>
  </div>

  <div id="canvasWrap">
    <div id="levelBadge">NÍVEL 1</div>
    <canvas id="c"></canvas>

    <div id="menuScreen" class="overlay">
      <h1>🌾 AGROTECH<br>RUSH</h1>
      <div class="subtitle">
        Itens caem representando problemas da lavoura. Toque na ação certa antes que caiam no chão! Combine ciência, agronomia e tecnologia pra salvar a colheita.
      </div>
      <div class="legend">
        <div>🥀→💧 Água</div>
        <div>🐛→🧪 Defensivo</div>
        <div>🍂→🌿 Adubo</div>
        <div>🔥→⛅ Sombra</div>
        <div>🌽→🌾 Colher</div>
        <div>🛰️ Drone = bônus!</div>
      </div>
      <button class="big" id="startBtn">🚀 COMEÇAR</button>
      <div class="best" id="menuBest">Recorde: 0</div>
    </div>

    <div id="factScreen" class="overlay hidden">
      <div id="factCard">
        <div class="tag">🔬 VOCÊ SABIA?</div>
        <p id="factText"></p>
      </div>
    </div>

    <div id="overScreen" class="overlay hidden">
      <h1 style="font-size:clamp(22px,7vw,40px)">🌾 FIM DE JOGO</h1>
      <div class="score-big" id="finalScore">0</div>
      <div class="best" id="overBest">Recorde: 0</div>
      <button class="big" id="retryBtn">🔁 JOGAR DE NOVO</button>
      <button class="ghost" id="shareBtn">📤 Copiar resultado</button>
    </div>
  </div>

  <div id="bins">
    <div class="bin" data-action="water"><div>💧</div><small>ÁGUA</small></div>
    <div class="bin" data-action="pest"><div>🧪</div><small>PRAGA</small></div>
    <div class="bin" data-action="fertilizer"><div>🌿</div><small>ADUBO</small></div>
    <div class="bin" data-action="shade"><div>⛅</div><small>SOMBRA</small></div>
    <div class="bin" data-action="harvest"><div>🌾</div><small>COLHER</small></div>
  </div>

</div>

<script>
(function(){
  "use strict";

  // ---------- Setup ----------
  var canvas = document.getElementById('c');
  var ctx = canvas.getContext('2d');
  var wrap = document.getElementById('canvasWrap');
  var DPR = Math.min(window.devicePixelRatio || 1, 2);

  function resize(){
    var w = wrap.clientWidth, h = wrap.clientHeight;
    canvas.width = w * DPR; canvas.height = h * DPR;
    canvas.style.width = w+'px'; canvas.style.height = h+'px';
    ctx.setTransform(DPR,0,0,DPR,0,0);
    W = w; H = h;
  }
  var W=0,H=0;
  window.addEventListener('resize', resize);
  resize();

  // ---------- Audio (WebAudio, no external files) ----------
  var actx = null;
  function ensureAudio(){
    if(!actx){
      try{ actx = new (window.AudioContext || window.webkitAudioContext)(); }catch(e){ actx = null; }
    }
  }
  function beep(freq, dur, type, vol){
    if(!actx) return;
    try{
      var o = actx.createOscillator();
      var g = actx.createGain();
      o.type = type || 'sine';
      o.frequency.value = freq;
      g.gain.value = 0;
      o.connect(g); g.connect(actx.destination);
      var t = actx.currentTime;
      g.gain.linearRampToValueAtTime(vol!==undefined?vol:0.18, t+0.01);
      g.gain.exponentialRampToValueAtTime(0.001, t + (dur||0.15));
      o.start(t);
      o.stop(t + (dur||0.15) + 0.02);
    }catch(e){}
  }
  function playGood(comboLevel){
    var base = 440 + Math.min(comboLevel,20)*18;
    beep(base, 0.12, 'square', 0.15);
    setTimeout(function(){ beep(base*1.5, 0.1, 'sine', 0.12); }, 60);
  }
  function playBad(){ beep(140, 0.28, 'sawtooth', 0.2); }
  function playWhiff(){ beep(220, 0.08, 'triangle', 0.08); }
  function playDrone(){
    beep(300,0.15,'sine',0.15);
    setTimeout(function(){beep(500,0.15,'sine',0.15);},90);
    setTimeout(function(){beep(760,0.2,'sine',0.18);},180);
  }
  function playLevelUp(){
    [520,660,880].forEach(function(f,i){ setTimeout(function(){beep(f,0.18,'square',0.16);}, i*100); });
  }

  // ---------- Game data ----------
  var TYPES = {
    water:      {emoji:'🥀', action:'water',      unlockLvl:1},
    pest:       {emoji:'🐛', action:'pest',        unlockLvl:2},
    fertilizer: {emoji:'🍂', action:'fertilizer',  unlockLvl:3},
    shade:      {emoji:'🔥', action:'shade',       unlockLvl:4},
    harvest:    {emoji:'🌽', action:'harvest',     unlockLvl:1}
  };
  var FACTS = [
    "Sensores de umidade no solo podem reduzir o uso de água na lavoura em até 30%.",
    "Drones agrícolas mapeiam plantações inteiras e identificam pragas antes que se espalhem.",
    "A rotação de culturas ajuda a manter os nutrientes do solo de forma natural.",
    "A agricultura de precisão usa GPS para aplicar água e adubo só onde é necessário.",
    "Minhocas melhoram a aeração do solo e aumentam a fertilidade da terra.",
    "O Brasil é um dos maiores produtores agrícolas do planeta.",
    "Compostagem transforma restos de comida em adubo rico em nutrientes.",
    "Estufas inteligentes ajustam temperatura e umidade automaticamente com sensores.",
    "Abelhas polinizam cerca de um terço de todos os alimentos que comemos.",
    "Biossensores conseguem detectar doenças em plantas antes de aparecerem sintomas visíveis.",
    "Satélites ajudam agricultores a prever safras e monitorar a saúde das plantas.",
    "Irrigação por gotejamento pode economizar até 60% de água comparado à irrigação tradicional."
  ];
  var usedFacts = [];
  function nextFact(){
    if(usedFacts.length >= FACTS.length) usedFacts = [];
    var pool = FACTS.filter(function(f){return usedFacts.indexOf(f)===-1;});
    var f = pool[Math.floor(Math.random()*pool.length)];
    usedFacts.push(f);
    return f;
  }

  var STORAGE_KEY = 'agrotech_rush_best';
  function getBest(){
    try{ return parseInt(localStorage.getItem(STORAGE_KEY)||'0',10) || 0; }catch(e){ return 0; }
  }
  function setBest(v){
    try{ localStorage.setItem(STORAGE_KEY, String(v)); }catch(e){}
  }

  // ---------- Game state ----------
  var state = 'menu'; // menu, playing, factpause, gameover
  var score = 0, combo = 0, comboMult = 1.0, lives = 3, level = 1;
  var correctSinceLevel = 0;
  var items = [];
  var particles = [];
  var shake = 0;
  var flashColor = null, flashAlpha = 0;
  var spawnTimer = 0, spawnInterval = 1400;
  var fallSpeedBase = 55; // px/sec
  var lastTime = 0;
  var droneCooldown = 0;

  var binEls = Array.prototype.slice.call(document.querySelectorAll('.bin'));

  function availableTypes(){
    var keys = Object.keys(TYPES).filter(function(k){ return TYPES[k].unlockLvl <= level; });
    return keys;
  }

  function resetGame(){
    score=0; combo=0; comboMult=1.0; lives=3; level=1; correctSinceLevel=0;
    items=[]; particles=[]; shake=0; flashAlpha=0;
    spawnTimer=0; spawnInterval=1400; fallSpeedBase=55; droneCooldown=3000;
    updateHUD();
  }

  function updateHUD(){
    document.getElementById('scoreVal').textContent = Math.floor(score);
    document.getElementById('comboVal').textContent = comboMult.toFixed(1);
    document.getElementById('hearts').textContent = '❤️'.repeat(Math.max(lives,0)) + '🖤'.repeat(Math.max(3-lives,0));
    document.getElementById('levelBadge').textContent = 'NÍVEL ' + level;
  }

  // ---------- Spawning ----------
  function spawnItem(){
    var avail = availableTypes();
    var isDrone = droneCooldown<=0 && Math.random() < 0.10;
    var key, typeInfo;
    if(isDrone){
      key = 'drone';
      typeInfo = {emoji:'🛰️', action:'drone'};
      droneCooldown = 9000 + Math.random()*4000;
    } else {
      key = avail[Math.floor(Math.random()*avail.length)];
      typeInfo = TYPES[key];
    }
    var r = Math.max(24, Math.min(W,H)*0.055);
    items.push({
      key:key,
      emoji: typeInfo.emoji,
      action: typeInfo.action,
      x: r + Math.random()*(W-2*r),
      y: -r,
      r: r,
      speed: fallSpeedBase + level*7 + Math.random()*20,
      wobble: Math.random()*Math.PI*2,
      resolved:false
    });
  }

  // ---------- Particles ----------
  function burst(x,y,color,n){
    for(var i=0;i<(n||14);i++){
      var a = Math.random()*Math.PI*2;
      var sp = 60+Math.random()*160;
      particles.push({
        x:x,y:y, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp,
        life:0.5+Math.random()*0.4, age:0, color:color, r:2+Math.random()*3
      });
    }
  }

  function triggerFlash(color){ flashColor=color; flashAlpha=0.35; }
  function triggerShake(amount){ shake = Math.max(shake, amount); }

  // ---------- Input handling ----------
  function pressBin(el){
    el.classList.add('pressed');
    setTimeout(function(){ el.classList.remove('pressed'); }, 90);
  }
  function flashBin(el, good){
    el.classList.add(good?'flash-good':'flash-bad');
    setTimeout(function(){ el.classList.remove(good?'flash-good':'flash-bad'); }, 180);
  }

  function handleBinTap(action, el){
    ensureAudio();
    if(state==='menu'){ return; }
    if(state!=='playing') return;
    pressBin(el);

    if(action==='drone'){
      // shouldn't happen, bins don't have drone action
    }

    // find best matching item: any drone on screen resolves on ANY bin tap
    var droneIdx = -1, matchIdx = -1, matchBestY = -1;
    for(var i=0;i<items.length;i++){
      var it = items[i];
      if(it.resolved) continue;
      if(it.action==='drone'){ droneIdx = i; }
      else if(it.action===action){
        if(it.y > matchBestY){ matchBestY = it.y; matchIdx = i; }
      }
    }

    if(droneIdx!==-1){
      resolveDrone(items[droneIdx]);
      flashBin(el,true);
      return;
    }

    if(matchIdx!==-1){
      resolveCorrect(items[matchIdx], el);
    } else {
      // whiff - no matching item currently falling
      flashBin(el,false);
      playWhiff();
      comboMult = Math.max(1.0, comboMult - 0.2);
      combo = 0;
      updateHUD();
    }
  }

  function resolveCorrect(it, el){
    it.resolved = true;
    combo++;
    comboMult = Math.min(3.0, 1.0 + combo*0.06);
    var heightFrac = 1 - (it.y / H); // 1 = caught near top, 0 = near bottom
    var basePts = 100 * (0.5 + heightFrac*1.0);
    var pts = basePts * comboMult;
    score += pts;
    correctSinceLevel++;
    burst(it.x, it.y, '#f4c542', 16);
    if(el) flashBin(el,true);
    playGood(combo);
    updateHUD();
    checkLevelUp();
  }

  function resolveDrone(it){
    it.resolved = true;
    var cleared = 0;
    items.forEach(function(o){
      if(!o.resolved && o.action!=='drone'){
        o.resolved = true; cleared++;
        burst(o.x,o.y,'#2ea7c9',10);
      }
    });
    var pts = 150 + cleared*40;
    score += pts * comboMult;
    combo += 2;
    comboMult = Math.min(3.0, 1.0 + combo*0.06);
    burst(it.x, it.y, '#2ea7c9', 26);
    triggerFlash('rgba(46,167,201,0.35)');
    playDrone();
    updateHUD();
  }

  function missItem(it){
    it.resolved = true;
    lives--;
    combo = 0; comboMult = 1.0;
    triggerShake(10);
    triggerFlash('rgba(224,80,58,0.35)');
    playBad();
    updateHUD();
    if(lives<=0){
      endGame();
    }
  }

  function checkLevelUp(){
    var need = 8 + level*2;
    if(correctSinceLevel >= need){
      correctSinceLevel = 0;
      level++;
      fallSpeedBase += 9;
      spawnInterval = Math.max(650, spawnInterval - 90);
      playLevelUp();
      showFact();
    }
  }

  binEls.forEach(function(el){
    var action = el.getAttribute('data-action');
    el.addEventListener('pointerdown', function(e){
      e.preventDefault();
      handleBinTap(action, el);
    });
  });

  // Keyboard support (1-5)
  window.addEventListener('keydown', function(e){
    var map = {'1':'water','2':'pest','3':'fertilizer','4':'shade','5':'harvest'};
    if(map[e.key] && state==='playing'){
      var idx = ['water','pest','fertilizer','shade','harvest'].indexOf(map[e.key]);
      handleBinTap(map[e.key], binEls[idx]);
    }
  });

  // ---------- Fact overlay ----------
  var factTimer = null;
  function showFact(){
    state = 'factpause';
    document.getElementById('factText').textContent = nextFact();
    document.getElementById('factScreen').classList.remove('hidden');
    clearTimeout(factTimer);
    factTimer = setTimeout(function(){
      document.getElementById('factScreen').classList.add('hidden');
      state = 'playing';
    }, 2200);
  }

  // ---------- Start / End ----------
  function startGame(){
    ensureAudio();
    resetGame();
    document.getElementById('menuScreen').classList.add('hidden');
    document.getElementById('overScreen').classList.add('hidden');
    document.getElementById('factScreen').classList.add('hidden');
    state = 'playing';
    lastTime = performance.now();
    requestAnimationFrame(loop);
  }

  function endGame(){
    state = 'gameover';
    var best = getBest();
    if(score > best){ best = Math.floor(score); setBest(best); }
    document.getElementById('finalScore').textContent = Math.floor(score);
    document.getElementById('overBest').textContent = 'Recorde: ' + best;
    document.getElementById('overScreen').classList.remove('hidden');
  }

  document.getElementById('startBtn').addEventListener('pointerdown', function(e){
    e.preventDefault(); startGame();
  });
  document.getElementById('retryBtn').addEventListener('pointerdown', function(e){
    e.preventDefault(); startGame();
  });
  document.getElementById('shareBtn').addEventListener('pointerdown', function(e){
    e.preventDefault();
    var txt = '🌾 Fiz ' + Math.floor(score) + ' pontos no AgroTech Rush! Consegue superar? 🚀 (jogo feito no ArcadeLab)';
    var done = function(){
      var b = document.getElementById('shareBtn');
      var old = b.textContent; b.textContent = '✅ Copiado!';
      setTimeout(function(){ b.textContent = old; }, 1400);
    };
    try{
      if(navigator.clipboard && navigator.clipboard.writeText){
        navigator.clipboard.writeText(txt).then(done).catch(function(){ fallbackCopy(txt, done); });
      } else {
        fallbackCopy(txt, done);
      }
    }catch(err){ fallbackCopy(txt, done); }
  });
  function fallbackCopy(txt, done){
    try{
      var ta = document.createElement('textarea');
      ta.value = txt; ta.style.position='fixed'; ta.style.opacity='0';
      document.body.appendChild(ta); ta.select();
      document.execCommand('copy');
      document.body.removeChild(ta);
      done();
    }catch(e){}
  }

  document.getElementById('menuBest').textContent = 'Recorde: ' + getBest();

  // ---------- Main loop ----------
  function loop(now){
    var dt = Math.min(0.05, (now - lastTime)/1000);
    lastTime = now;

    if(state==='playing'){
      spawnTimer += dt*1000;
      if(spawnTimer >= spawnInterval){
        spawnTimer = 0;
        spawnItem();
      }
      droneCooldown -= dt*1000;

      for(var i=items.length-1;i>=0;i--){
        var it = items[i];
        if(it.resolved) continue;
        it.y += it.speed * dt;
        it.wobble += dt*2;
        if(it.y - it.r > H){
          if(it.action==='drone'){
            it.resolved = true; // drone just leaves harmlessly
          } else {
            missItem(it);
          }
        }
      }
      items = items.filter(function(it){ return !(it.resolved && it.y > H+50) && it.y < H+80; });
      items = items.filter(function(it){ return it.y < H + 60 || !it.resolved; });
    }

    for(var p=particles.length-1;p>=0;p--){
      var pt = particles[p];
      pt.age += dt;
      if(pt.age >= pt.life){ particles.splice(p,1); continue; }
      pt.x += pt.vx*dt; pt.y += pt.vy*dt;
      pt.vy += 220*dt;
    }

    if(shake>0){ shake = Math.max(0, shake - dt*30); }
    if(flashAlpha>0){ flashAlpha = Math.max(0, flashAlpha - dt*0.8); }

    render();
    requestAnimationFrame(loop);
  }

  function render(){
    ctx.clearRect(0,0,W,H);
    ctx.save();
    if(shake>0){
      var sx = (Math.random()-0.5)*shake, sy=(Math.random()-0.5)*shake;
      ctx.translate(sx,sy);
    }

    // background field stripes
    ctx.fillStyle = '#0e3719';
    ctx.fillRect(0,0,W,H);
    ctx.globalAlpha = 0.5;
    for(var s=0;s<6;s++){
      ctx.fillStyle = s%2===0 ? '#124020' : '#0e3719';
      ctx.fillRect(0, H*(s/6), W, H/6);
    }
    ctx.globalAlpha = 1;

    // danger line
    ctx.strokeStyle = 'rgba(224,80,58,0.35)';
    ctx.lineWidth = 2;
    ctx.setLineDash([8,6]);
    ctx.beginPath();
    ctx.moveTo(0, H-6); ctx.lineTo(W, H-6);
    ctx.stroke();
    ctx.setLineDash([]);

    // items
    items.forEach(function(it){
      if(it.resolved) return;
      var wob = Math.sin(it.wobble)*4;
      ctx.save();
      ctx.translate(it.x + wob, it.y);
      ctx.font = (it.r*1.7)+'px serif';
      ctx.textAlign='center'; ctx.textBaseline='middle';
      // glow circle
      ctx.beginPath();
      ctx.fillStyle = it.action==='drone' ? 'rgba(46,167,201,0.25)' : 'rgba(244,197,66,0.18)';
      ctx.arc(0,0,it.r*1.15,0,Math.PI*2);
      ctx.fill();
      ctx.fillText(it.emoji, 0, 2);
      ctx.restore();
    });

    // particles
    particles.forEach(function(pt){
      var alpha = 1 - pt.age/pt.life;
      ctx.globalAlpha = Math.max(0,alpha);
      ctx.fillStyle = pt.color;
      ctx.beginPath();
      ctx.arc(pt.x, pt.y, pt.r, 0, Math.PI*2);
      ctx.fill();
      ctx.globalAlpha = 1;
    });

    ctx.restore();

    if(flashAlpha>0 && flashColor){
      ctx.fillStyle = flashColor.replace(/[\d.]+\)$/, flashAlpha+')');
      ctx.fillRect(0,0,W,H);
    }
  }

  render();
})();
</script>
</body>
</html>

Game Source: AgroTech Rush

Creator: StormGecko10

Libraries: none

Complexity: complex (642 lines, 21.2 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: agrotech-rush-stormgecko10" to link back to the original. Then publish at arcadelab.ai/publish.