울티마 골드 빨리 벌고 싶어서 만들었어요
스테이지별 골드는 한자님의 메이플 AI를 참고해서 만들었습니다
텍스트라서 메모장에 붙여넣기 하고 확장자를 .html로 변경해서 사용하시면 됩니다
파일은 못올려서 전문 올렸습니다
자유롭게 바꿔서 사용하시면 됩니다~
다들 즐메

이렇게 나옵니다
시간 입력시 하단에 어디 구간이 골드 효율 가장 높은지 나와요



<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>스테이지 초당 골드 계산기</title>
<style>
  :root{
    --bg:#0b0f1a;
    --panel:#141b2b;
    --panel2:#1a2338;
    --border:#293349;
    --border-strong:#3a4560;
    --gold:#f0b132;
    --gold-dim:#c98f22;
    --green:#3ecf6e;
    --green-bg:rgba(62,207,110,0.12);
    --text:#e8e9ee;
    --text-dim:#8992a8;
    --danger:#e2534a;
    --chaos:#b06bff;
    --chaos-bg:rgba(176,107,255,0.12);
  }
  *{box-sizing:border-box;}
  body{
    margin:0;
    background:radial-gradient(circle at 50% 0%, #131c30 0%, var(--bg) 60%);
    color:var(--text);
    font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Malgun Gothic",sans-serif;
    padding:16px 10px 60px;
  }
  .wrap{max-width:820px;margin:0 auto;}
  h1{
    font-size:19px;
    font-weight:700;
    margin:0 0 4px;
    color:var(--gold);
    letter-spacing:0.2px;
    text-shadow:0 0 12px rgba(240,177,50,0.35);
  }
  .sub{color:var(--text-dim);font-size:12px;margin:0 0 16px;}

  .mode-tabs{
    display:flex;
    gap:8px;
    margin-bottom:14px;
  }
  .mode-tab{
    flex:1;
    padding:10px;
    text-align:center;
    border-radius:10px;
    border:1px solid var(--border);
    background:var(--panel);
    color:var(--text-dim);
    font-weight:700;
    font-size:14px;
    cursor:pointer;
    transition:all .15s;
  }
  .mode-tab.active[data-mode="normal"]{
    color:var(--gold);
    border-color:var(--gold-dim);
    background:linear-gradient(180deg, rgba(240,177,50,0.15), var(--panel));
    box-shadow:0 0 14px rgba(240,177,50,0.15) inset;
  }
  .mode-tab.active[data-mode="chaos"]{
    color:var(--chaos);
    border-color:var(--chaos);
    background:linear-gradient(180deg, rgba(176,107,255,0.15), var(--panel));
    box-shadow:0 0 14px rgba(176,107,255,0.2) inset;
  }

  .panel{display:none;}
  .panel.active{display:block;}

  .card{
    background:var(--panel);
    border:1px solid var(--border);
    border-radius:12px;
    padding:14px;
    margin-bottom:14px;
  }
  .card h2{font-size:13px;font-weight:600;color:var(--text-dim);margin:0 0 10px;letter-spacing:0.3px;}

  .toprow{
    display:flex;
    align-items:center;
    gap:10px;
    flex-wrap:wrap;
  }
  .toprow label{font-size:13px;color:var(--text-dim);white-space:nowrap;}
  .toprow input{
    width:80px;
    background:var(--panel2);
    border:1px solid var(--border);
    border-radius:8px;
    color:var(--gold);
    font-size:16px;
    font-weight:700;
    padding:8px 10px;
    text-align:center;
  }
  .toprow input:focus{outline:none;border-color:var(--gold-dim);}
  .toprow .pct{color:var(--text-dim);font-size:13px;}

  .save-note{font-size:11px;color:var(--text-dim);margin-left:auto;transition:color .2s;}
  .save-note.visible{color:var(--green);}

  .btnrow{display:flex;gap:8px;margin-left:auto;flex-wrap:wrap;}
  .btn{
    background:var(--panel2);
    border:1px solid var(--border-strong);
    color:var(--text);
    border-radius:8px;
    padding:7px 12px;
    font-size:12px;
    cursor:pointer;
    white-space:nowrap;
  }
  .btn:hover{border-color:var(--gold-dim);color:var(--gold);}
  .btn.danger:hover{border-color:var(--danger);color:var(--danger);}

  .table-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;}
  table{width:100%;border-collapse:collapse;font-size:12.5px;}
  thead th{
    text-align:center;color:var(--text-dim);font-weight:600;font-size:11px;
    padding:6px 4px;border-bottom:1px solid var(--border-strong);white-space:nowrap;
  }
  tbody td{padding:5px 4px;text-align:center;border-bottom:1px solid var(--border);white-space:nowrap;}
  tbody tr.best td{background:var(--green-bg);}
  tbody tr.best td:first-child{border-left:3px solid var(--green);}
  .stage-input,.time-input,.base-input{
    width:100%;min-width:50px;background:var(--panel2);border:1px solid var(--border);
    border-radius:6px;color:var(--text);font-size:12.5px;padding:6px 4px;text-align:center;
  }
  .stage-input{min-width:58px;}
  .stage-input:focus,.time-input:focus,.base-input:focus{outline:none;border-color:var(--gold-dim);}
  .gps{color:var(--gold);font-weight:700;font-size:13.5px;}
  tr.best .gps{color:var(--green);}
  .del-btn{background:none;border:none;color:var(--text-dim);font-size:15px;cursor:pointer;padding:2px 6px;line-height:1;}
  .del-btn:hover{color:var(--danger);}

  .add-btn{
    width:100%;margin-top:10px;background:var(--panel2);border:1px dashed var(--border-strong);
    color:var(--gold);border-radius:8px;padding:10px;font-size:13px;cursor:pointer;
  }
  .add-btn:hover{border-color:var(--gold-dim);}

  .best-summary{
    margin-top:0;padding:12px 14px;background:var(--green-bg);
    border:1px solid rgba(62,207,110,0.35);border-radius:10px;font-size:13px;
  }
  .best-summary b{color:var(--green);font-size:15px;}

  .chart-row{display:flex;align-items:center;gap:8px;margin-bottom:8px;}
  .chart-rank{width:20px;font-size:11px;color:var(--text-dim);text-align:right;flex-shrink:0;}
  .chart-label{width:56px;font-size:12px;color:var(--text);flex-shrink:0;}
  .chart-bar-bg{flex:1;background:var(--panel2);border-radius:6px;height:20px;overflow:hidden;position:relative;}
  .chart-bar-fill{height:100%;border-radius:6px;background:linear-gradient(90deg, var(--gold-dim), var(--gold));}
  .chart-bar-fill.top{background:linear-gradient(90deg, #1f8f4a, var(--green));}
  .chart-val{width:78px;font-size:11.5px;color:var(--text-dim);text-align:right;flex-shrink:0;}
  .crown{color:#ffd85e;margin-right:2px;}

  .formula{font-size:11.5px;color:var(--text-dim);line-height:1.7;margin-top:10px;}
  .formula code{color:var(--gold-dim);}
</style>
</head>
<body>
<div class="wrap">
  <h1>스테이지 초당 골드 계산기</h1>
  <p class="sub">일반 몬스터 60마리 + 보스(적용골드×20) 기준 · 일반 / 카오스 모드 지원</p>

  <div class="mode-tabs">
    <div class="mode-tab active" data-mode="normal" id="tabNormal">일반 모드</div>
    <div class="mode-tab" data-mode="chaos" id="tabChaos">카오스 모드</div>
  </div>

  <div id="panelNormal" class="panel active"></div>
  <div id="panelChaos" class="panel"></div>
</div>

<script>
const PANEL_TEMPLATE = (mode) => `
  <div class="card">
    <div class="toprow">
      <label>골드 획득량</label>
      <input type="text" inputmode="decimal" id="rate-${mode}" style="width:70px;">
      <span class="pct">%</span>
      <label style="margin-left:6px;">몬스터 마리수</label>
      <input type="text" inputmode="decimal" id="monsterCount-${mode}" style="width:60px;">
      <label style="margin-left:6px;">보스 마리수</label>
      <input type="text" inputmode="decimal" id="bossCount-${mode}" style="width:60px;">
      <span class="save-note" id="saveNote-${mode}">저장됨</span>
      <div class="btnrow">
        <button class="btn" id="saveBtn-${mode}">저장</button>
        <button class="btn" id="csvBtn-${mode}">CSV 내보내기</button>
        <button class="btn danger" id="resetBtn-${mode}">초기화</button>
      </div>
    </div>
  </div>

  <div class="card">
    <div class="table-scroll">
      <table>
        <thead>
          <tr>
            <th>스테이지</th><th>기본골드</th><th>클리어 시간</th><th>총 골드</th><th>초당 골드</th><th>30분당</th><th>1시간당</th><th></th>
          </tr>
        </thead>
        <tbody id="rows-${mode}"></tbody>
      </table>
    </div>
    <button class="add-btn" id="addBtn-${mode}">+ 스테이지 추가</button>
    <div class="formula">
      적용골드 = 기본골드 × (1 + 획득량%) &nbsp;·&nbsp; 총골드 = (적용골드 × 몬스터 마리수) + (적용골드 × 20 × 보스 마리수) &nbsp;·&nbsp; 초당골드 = 총골드 ÷ 클리어시간(초) &nbsp;·&nbsp; 시간당골드 = 초당골드 × 3600<br>
      몬스터/보스 마리수는 스테이지별이 아닌 모드 전체 공통값이며 0으로도 설정할 수 있어요. 시간 입력은 <code>1:33</code> 또는 <code>93</code> 형식 모두 가능
    </div>
  </div>

  <div class="best-summary" id="bestSummary-${mode}"></div>

  <div class="card">
    <h2>효율 순위 (초당 골드 기준)</h2>
    <div id="chart-${mode}"></div>
  </div>
`;

document.getElementById('panelNormal').innerHTML = PANEL_TEMPLATE('normal');
document.getElementById('panelChaos').innerHTML = PANEL_TEMPLATE('chaos');

function buildDefaultStages(){
  const stages = [];
  const areaBase = { 1:[10,30,50,70,90,110,130,150,170], 2:[400,430,460,490,520,550,580,610,640] };
  for(let area=1; area<=3; area++){
    for(let n=1; n<=9; n++){
      const base = (areaBase[area] && areaBase[area][n-1] !== undefined) ? areaBase[area][n-1] : 0;
      let time = '';
      if(area===1 && n===7) time='1:33';
      if(area===1 && n===8) time='2:18';
      if(area===1 && n===9) time='2:56';
      stages.push({ stage:`${area}-${n}`, base, time });
    }
  }
  return stages;
}

const MODES = {
  normal: {
    rateKey:'gold-calc-normal-rate-v2',
    stagesKey:'gold-calc-normal-stages-v2',
    countsKey:'gold-calc-normal-counts-v2',
    defaultRate: 15,
    defaultMonsterCount: 60,
    defaultBossCount: 1,
    defaultStages: buildDefaultStages()
  },
  chaos: {
    rateKey:'gold-calc-chaos-rate-v2',
    stagesKey:'gold-calc-chaos-stages-v2',
    countsKey:'gold-calc-chaos-counts-v2',
    defaultRate: 15,
    defaultMonsterCount: 60,
    defaultBossCount: 1,
    defaultStages: buildDefaultStages().map(s => ({ stage:s.stage, base:0, time:'' }))
  }
};

const state = {
  normal: { rate: MODES.normal.defaultRate, monsterCount: MODES.normal.defaultMonsterCount, bossCount: MODES.normal.defaultBossCount, stages: JSON.parse(JSON.stringify(MODES.normal.defaultStages)) },
  chaos:  { rate: MODES.chaos.defaultRate,  monsterCount: MODES.chaos.defaultMonsterCount,  bossCount: MODES.chaos.defaultBossCount,  stages: JSON.parse(JSON.stringify(MODES.chaos.defaultStages)) }
};
const saveTimers = {};

function parseTime(str){
  if(str === null || str === undefined) return 0;
  str = String(str).trim();
  if(str === '') return 0;
  if(str.includes(':')){
    const parts = str.split(':').map(p => parseFloat(p) || 0);
    if(parts.length === 2) return parts[0]*60 + parts[1];
    if(parts.length === 3) return parts[0]*3600 + parts[1]*60 + parts[2];
    return 0;
  }
  const n = parseFloat(str);
  return isNaN(n) ? 0 : n;
}
function formatNum(n){ return Math.round(n).toLocaleString('ko-KR'); }

function computeRow(row, rate, monsterCount, bossCount){
  const base = parseFloat(row.base) || 0;
  const seconds = parseTime(row.time);
  const applied = base * (1 + rate/100);
  const mCount = (typeof monsterCount === 'number' && !isNaN(monsterCount)) ? monsterCount : 60;
  const bCount = (typeof bossCount === 'number' && !isNaN(bossCount)) ? bossCount : 1;
  const total = applied*mCount + applied*20*bCount;
  const gps = seconds > 0 ? total/seconds : 0;
  const gph = gps*3600;
  const gp30 = gps*1800;
  return { applied, total, seconds, gps, gph, gp30 };
}

const storageAPI = {
  async get(key){
    if(typeof window.storage !== 'undefined' && window.storage){
      try{ return await window.storage.get(key, false); }
      catch(e){ /* fall through to localStorage */ }
    }
    try{
      const v = localStorage.getItem(key);
      return v !== null ? { key, value: v, shared:false } : null;
    }catch(e){ return null; }
  },
  async set(key, value){
    if(typeof window.storage !== 'undefined' && window.storage){
      try{ return await window.storage.set(key, value, false); }
      catch(e){ /* fall through to localStorage */ }
    }
    try{
      localStorage.setItem(key, value);
      return { key, value, shared:false };
    }catch(e){ return null; }
  }
};

const rowRefs = { normal: [], chaos: [] };

function readCounts(mode){
  const m = state[mode];
  const monsterInput = document.getElementById(`monsterCount-${mode}`);
  const bossInput = document.getElementById(`bossCount-${mode}`);
  const mVal = parseFloat(monsterInput.value);
  const bVal = parseFloat(bossInput.value);
  m.monsterCount = isNaN(mVal) ? 0 : mVal;
  m.bossCount = isNaN(bVal) ? 0 : bVal;
  return m;
}

function render(mode){
  // Full rebuild: only call when rows are added/removed/reset/loaded.
  const m = state[mode];
  const rateInput = document.getElementById(`rate-${mode}`);
  m.rate = parseFloat(rateInput.value) || 0;
  readCounts(mode);

  const tbody = document.getElementById(`rows-${mode}`);
  tbody.innerHTML = '';
  rowRefs[mode] = [];

  m.stages.forEach((row, i) => {
    const tr = document.createElement('tr');

    const tdStage = document.createElement('td');
    const stageInput = document.createElement('input');
    stageInput.className = 'stage-input';
    stageInput.value = row.stage;
    stageInput.addEventListener('input', e => { m.stages[i].stage = e.target.value; scheduleSave(mode); renderSummaryAndChart(mode); });
    tdStage.appendChild(stageInput);

    const tdBase = document.createElement('td');
    const baseInput = document.createElement('input');
    baseInput.className = 'base-input';
    baseInput.type = 'text';
    baseInput.inputMode = 'decimal';
    baseInput.value = row.base;
    baseInput.addEventListener('input', e => { m.stages[i].base = e.target.value; updateCalcs(mode); });
    tdBase.appendChild(baseInput);

    const tdTime = document.createElement('td');
    const timeInput = document.createElement('input');
    timeInput.className = 'time-input';
    timeInput.placeholder = '1:33';
    timeInput.value = row.time;
    timeInput.addEventListener('input', e => { m.stages[i].time = e.target.value; updateCalcs(mode); });
    tdTime.appendChild(timeInput);

    const tdTotal = document.createElement('td');
    const tdGps = document.createElement('td');
    tdGps.className = 'gps';
    const tdGp30 = document.createElement('td');
    const tdGph = document.createElement('td');

    const tdDel = document.createElement('td');
    const delBtn = document.createElement('button');
    delBtn.className = 'del-btn';
    delBtn.textContent = '✕';
    delBtn.addEventListener('click', () => { m.stages.splice(i,1); render(mode); scheduleSave(mode); });
    tdDel.appendChild(delBtn);

    tr.appendChild(tdStage); tr.appendChild(tdBase); tr.appendChild(tdTime);
    tr.appendChild(tdTotal); tr.appendChild(tdGps); tr.appendChild(tdGp30); tr.appendChild(tdGph); tr.appendChild(tdDel);
    tbody.appendChild(tr);

    rowRefs[mode].push({ tr, tdTotal, tdGps, tdGp30, tdGph });
  });

  updateCalcs(mode);
}

function updateCalcs(mode){
  // Recompute and update only the calculated cells + best-row highlight.
  // Never touches the stage/base/time <input> elements, so focus and cursor
  // position are preserved while typing.
  const m = state[mode];
  const rateInput = document.getElementById(`rate-${mode}`);
  m.rate = parseFloat(rateInput.value) || 0;
  readCounts(mode);

  const computed = m.stages.map(row => computeRow(row, m.rate, m.monsterCount, m.bossCount));
  let bestIdx = -1, bestGps = -1;
  computed.forEach((calc,i) => { if(calc.seconds > 0 && calc.gps > bestGps){ bestGps = calc.gps; bestIdx = i; } });

  rowRefs[mode].forEach((refs, i) => {
    const calc = computed[i];
    refs.tr.className = (i === bestIdx) ? 'best' : '';
    refs.tdTotal.textContent = formatNum(calc.total) + 'G';
    refs.tdGps.textContent = calc.seconds > 0 ? formatNum(calc.gps) + '/s' : '-';
    refs.tdGp30.textContent = calc.seconds > 0 ? formatNum(calc.gp30) + 'G' : '-';
    refs.tdGph.textContent = calc.seconds > 0 ? formatNum(calc.gph) + 'G' : '-';
  });

  renderSummaryAndChart(mode);
  scheduleSave(mode);
}

function renderSummaryAndChart(mode){
  const m = state[mode];
  const computed = m.stages.map(row => ({ row, calc: computeRow(row, m.rate, m.monsterCount, m.bossCount) }))
    .filter(item => item.calc.seconds > 0)
    .sort((a,b) => b.calc.gps - a.calc.gps);

  const summary = document.getElementById(`bestSummary-${mode}`);
  if(computed.length > 0){
    const b = computed[0];
    summary.innerHTML = `가장 효율 좋은 스테이지: <b>${b.row.stage}</b> — 초당 ${formatNum(b.calc.gps)}G · 시간당 ${formatNum(b.calc.gph)}G (총 ${formatNum(b.calc.total)}G / ${formatNum(b.calc.seconds)}초)`;
  } else {
    summary.innerHTML = '클리어 시간을 입력하면 추천 스테이지가 표시됩니다.';
  }

  const chart = document.getElementById(`chart-${mode}`);
  chart.innerHTML = '';
  if(computed.length === 0){
    chart.innerHTML = '<div style="color:var(--text-dim);font-size:12px;">시간이 입력된 스테이지가 없습니다.</div>';
    return;
  }
  const maxGps = computed[0].calc.gps;
  computed.forEach((item, i) => {
    const row = document.createElement('div');
    row.className = 'chart-row';
    const pct = maxGps > 0 ? (item.calc.gps/maxGps*100) : 0;
    row.innerHTML = `
      <div class="chart-rank">${i===0 ? '<span class="crown">👑</span>' : (i+1)}</div>
      <div class="chart-label">${item.row.stage}</div>
      <div class="chart-bar-bg"><div class="chart-bar-fill${i===0?' top':''}" style="width:${pct}%"></div></div>
      <div class="chart-val">${formatNum(item.calc.gps)}/s</div>
    `;
    chart.appendChild(row);
  });
}

function scheduleSave(mode){
  clearTimeout(saveTimers[mode]);
  saveTimers[mode] = setTimeout(() => saveState(mode), 500);
}

async function saveState(mode, manual){
  const saveBtn = document.getElementById(`saveBtn-${mode}`);
  try{
    await storageAPI.set(MODES[mode].stagesKey, JSON.stringify(state[mode].stages));
    await storageAPI.set(MODES[mode].rateKey, JSON.stringify(state[mode].rate));
    await storageAPI.set(MODES[mode].countsKey, JSON.stringify({ monsterCount: state[mode].monsterCount, bossCount: state[mode].bossCount }));
    const note = document.getElementById(`saveNote-${mode}`);
    note.textContent = '저장됨';
    note.classList.add('visible');
    setTimeout(() => note.classList.remove('visible'), 1200);
    if(manual){
      const original = saveBtn.textContent;
      saveBtn.textContent = '저장됨 ✓';
      saveBtn.disabled = true;
      setTimeout(() => { saveBtn.textContent = original; saveBtn.disabled = false; }, 1000);
    }
  }catch(err){
    console.error('save failed', err);
    if(manual){
      const original = saveBtn.textContent;
      saveBtn.textContent = '저장 실패';
      setTimeout(() => { saveBtn.textContent = original; }, 1500);
    }
  }
}

async function loadState(mode){
  try{
    const savedStages = await storageAPI.get(MODES[mode].stagesKey);
    if(savedStages && savedStages.value) state[mode].stages = JSON.parse(savedStages.value);
  }catch(err){}
  try{
    const savedRate = await storageAPI.get(MODES[mode].rateKey);
    if(savedRate && savedRate.value) state[mode].rate = JSON.parse(savedRate.value);
  }catch(err){}
  try{
    const savedCounts = await storageAPI.get(MODES[mode].countsKey);
    if(savedCounts && savedCounts.value){
      const parsed = JSON.parse(savedCounts.value);
      state[mode].monsterCount = parsed.monsterCount;
      state[mode].bossCount = parsed.bossCount;
    }
  }catch(err){}
  document.getElementById(`rate-${mode}`).value = state[mode].rate;
  document.getElementById(`monsterCount-${mode}`).value = state[mode].monsterCount;
  document.getElementById(`bossCount-${mode}`).value = state[mode].bossCount;
  render(mode);
}

function exportCSV(mode){
  const m = state[mode];
  const rows = m.stages.map(row => {
    const c = computeRow(row, m.rate, m.monsterCount, m.bossCount);
    return [row.stage, row.base, row.time, Math.round(c.applied), Math.round(c.total), c.seconds, Math.round(c.gps), Math.round(c.gp30), Math.round(c.gph)];
  });
  const header = ['스테이지','기본골드','클리어시간(초)','적용골드','총골드','시간(초)','초당골드','30분당골드','시간당골드'];
  const meta = [`몬스터 마리수,${m.monsterCount}`, `보스 마리수,${m.bossCount}`, `골드 획득량(%),${m.rate}`, ''];
  const csvLines = [...meta, header.join(','), ...rows.map(r => r.join(','))];
  const csv = 'uFEFF' + csvLines.join('n');
  const blob = new Blob([csv], { type:'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `${mode}_gold_stages.csv`;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}

function resetMode(mode){
  state[mode].rate = MODES[mode].defaultRate;
  state[mode].monsterCount = MODES[mode].defaultMonsterCount;
  state[mode].bossCount = MODES[mode].defaultBossCount;
  state[mode].stages = JSON.parse(JSON.stringify(MODES[mode].defaultStages));
  document.getElementById(`rate-${mode}`).value = state[mode].rate;
  document.getElementById(`monsterCount-${mode}`).value = state[mode].monsterCount;
  document.getElementById(`bossCount-${mode}`).value = state[mode].bossCount;
  render(mode);
  scheduleSave(mode);
}

['normal','chaos'].forEach(mode => {
  document.getElementById(`rate-${mode}`).addEventListener('input', () => updateCalcs(mode));
  document.getElementById(`monsterCount-${mode}`).addEventListener('input', () => updateCalcs(mode));
  document.getElementById(`bossCount-${mode}`).addEventListener('input', () => updateCalcs(mode));
  document.getElementById(`addBtn-${mode}`).addEventListener('click', () => {
    state[mode].stages.push({ stage:'새 스테이지', base:0, time:'' });
    render(mode);
  });
  document.getElementById(`csvBtn-${mode}`).addEventListener('click', () => exportCSV(mode));
  document.getElementById(`saveBtn-${mode}`).addEventListener('click', () => {
    clearTimeout(saveTimers[mode]);
    saveState(mode, true);
  });
  document.getElementById(`resetBtn-${mode}`).addEventListener('click', () => {
    if(confirm('이 모드의 모든 값을 초기 상태로 되돌릴까요?')) resetMode(mode);
  });
  loadState(mode);
});

document.getElementById('tabNormal').addEventListener('click', () => switchTab('normal'));
document.getElementById('tabChaos').addEventListener('click', () => switchTab('chaos'));
function switchTab(mode){
  document.getElementById('tabNormal').classList.toggle('active', mode==='normal');
  document.getElementById('tabChaos').classList.toggle('active', mode==='chaos');
  document.getElementById('panelNormal').classList.toggle('active', mode==='normal');
  document.getElementById('panelChaos').classList.toggle('active', mode==='chaos');
}
</script>
</body>
</html>


열심히 만들었는데 사용하고 후기 알려주시면 감사하겠습니다ㅏㅏㅏ