空调模拟器 edit icon

创建者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
index.html
            
            <!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>空调模拟器 · AIR SIMULATOR</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&family=Share+Tech+Mono&family=ZCOOL+QingKe+HuangYou&display=swap" rel="stylesheet">
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{
  --disp:'ZCOOL QingKe HuangYou',system-ui;
  --body:'Noto Sans SC',system-ui;
  --digi:'Share Tech Mono',monospace;
}
html,body{min-height:100%}
body{
  font-family:var(--body);color:var(--ink);background:var(--page);
  transition:background .6s,color .6s;-webkit-user-select:none;user-select:none;
}
/* ================= 品牌配色 ================= */
body[data-brand=gree]  {--acc:#0ba45e;--acc2:#07743f;--led:#5dff9e}
body[data-brand=midea] {--acc:#1489d6;--acc2:#0b5f9a;--led:#6fdcff}
body[data-brand=haier] {--acc:#2f6bff;--acc2:#1c46c2;--led:#8fb5ff}
body[data-brand=mijia] {--acc:#ff7a1a;--acc2:#c95700;--led:#ffcf8f}
body[data-brand=daikin]{--acc:#00b3c8;--acc2:#007e90;--led:#79f2ff}
/* ================= 主题 ================= */
body[data-theme=day]{
  --page:#dfe6ec;--ink:#1f2a35;--chipbg:#ffffff;--chipink:#1f2a35;
  --panel:#ffffff;--panel2:#f0f5f8;--line:#d3dde5;--frame:#fbfdff;
  --wall1:#eef2f5;--wall2:#d7dfe7;--floor1:#c8a06b;--floor2:#a97f4e;--shadow:rgba(30,50,70,.18);
}
body[data-theme=night]{
  --page:#10151f;--ink:#e8edf7;--chipbg:#222c40;--chipink:#e8edf7;
  --panel:#1a2334;--panel2:#141c2b;--line:#2e3c57;--frame:#cfd6e4;
  --wall1:#2a3450;--wall2:#1a2336;--floor1:#4a3a33;--floor2:#332723;--shadow:rgba(0,0,0,.55);
}
body[data-theme=sunset]{
  --page:#f3dcc8;--ink:#3c2530;--chipbg:#fff6ec;--chipink:#4a2c36;
  --panel:#fff3e6;--panel2:#f6e2cf;--line:#e6c7ad;--frame:#fff7ef;
  --wall1:#f8e7d6;--wall2:#eecbb1;--floor1:#b07a4e;--floor2:#8f5c38;--shadow:rgba(90,40,40,.22);
}
body[data-theme=tech]{
  --page:#0a0e13;--ink:#d8f4ee;--chipbg:#12222b;--chipink:#d8f4ee;
  --panel:#101a22;--panel2:#0c141b;--line:#1f3a46;--frame:#22343f;
  --wall1:#131c26;--wall2:#0b1219;--floor1:#20303a;--floor2:#141f27;--shadow:rgba(0,0,0,.6);
}
.app{max-width:1180px;margin:0 auto;padding:0 20px 34px}
/* ================= 顶栏 ================= */
.topbar{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:18px 2px 14px;animation:rise .6s both}
.logo{font-family:var(--disp);font-size:30px;letter-spacing:3px;line-height:1}
.logo small{display:block;font-family:var(--digi);font-size:11px;letter-spacing:6px;color:var(--acc);margin-top:5px;transition:color .4s}
.top-right{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.chip{background:var(--chipbg);color:var(--chipink);border:1px solid var(--line);border-radius:999px;
  padding:7px 14px;font-size:13px;box-shadow:0 2px 8px var(--shadow);transition:background .5s,color .5s}
.chip b{font-family:var(--digi);font-size:15px}
#btnSettings{cursor:pointer;display:inline-flex;align-items:center;gap:7px;font-weight:600;transition:.25s}
#btnSettings:hover{transform:translateY(-1px);border-color:var(--acc)}
#btnSettings .chev{display:inline-block;transition:transform .4s;font-size:11px}
#btnSettings.open .chev{transform:rotate(180deg)}
/* ================= 可折叠设置面板 ================= */
.panel{display:grid;grid-template-rows:0fr;transition:grid-template-rows .5s cubic-bezier(.4,0,.2,1)}
.panel.open{grid-template-rows:1fr}
.panel-in{overflow:hidden}
.panel-card{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:20px 22px;
  display:grid;grid-template-columns:1.25fr 1fr .7fr;gap:28px;margin-bottom:18px;transition:background .5s}
.p-group h3{font-family:var(--disp);font-size:17px;letter-spacing:3px;margin-bottom:13px;display:flex;align-items:center;gap:9px;font-weight:400}
.p-group h3::before{content:'';width:9px;height:9px;background:var(--acc);border-radius:2px;transition:background .4s}
.brands{display:grid;grid-template-columns:repeat(5,1fr);gap:8px}
.b-btn{border:1.5px solid var(--line);background:var(--panel2);border-radius:12px;padding:10px 4px;cursor:pointer;
  text-align:center;transition:.22s;color:var(--chipink);font-family:var(--body)}
.b-btn .dot{width:11px;height:11px;border-radius:50%;margin:0 auto 7px;background:var(--bc)}
.b-btn span{font-size:12.5px;font-weight:600}
.b-btn:hover{transform:translateY(-2px)}
.b-btn.on{border-color:var(--bc);background:var(--chipbg);box-shadow:0 0 0 3px color-mix(in srgb,var(--bc) 22%,transparent)}
.themes{display:grid;grid-template-columns:repeat(2,1fr);gap:9px}
.t-btn{border:1.5px solid var(--line);background:var(--panel2);border-radius:12px;padding:7px;cursor:pointer;transition:.22s;color:var(--chipink)}
.t-btn .sw{height:36px;border-radius:8px;margin-bottom:6px;background:var(--pv)}
.t-btn span{font-size:12px;font-weight:600}
.t-btn:hover{transform:translateY(-2px)}
.t-btn.on{border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 22%,transparent)}
.opts{display:flex;flex-direction:column;gap:12px}
.switch-row{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:13.5px;cursor:pointer}
.switch-row input{display:none}
.switch-row .track{width:42px;height:23px;border-radius:999px;background:var(--line);position:relative;transition:.3s;flex:none}
.switch-row .track::after{content:'';position:absolute;left:3px;top:3px;width:17px;height:17px;border-radius:50%;background:#fff;transition:.3s;box-shadow:0 1px 3px rgba(0,0,0,.3)}
.switch-row input:checked+.track{background:var(--acc)}
.switch-row input:checked+.track::after{left:22px}
/* ================= 主布局 ================= */
.main{display:grid;grid-template-columns:minmax(0,1fr) 292px;gap:22px;align-items:stretch}
/* ================= 房间场景 ================= */
.scene{position:relative;border-radius:20px;overflow:hidden;min-height:560px;border:1px solid var(--line);
  background:linear-gradient(var(--wall1),var(--wall2));box-shadow:0 16px 44px var(--shadow);
  transition:background .6s;animation:rise .7s .05s both}
.scene::before{content:'';position:absolute;inset:0;pointer-events:none;opacity:.5;
  background:repeating-linear-gradient(0deg,transparent 0 46px,rgba(0,0,0,.025) 46px 47px)}
body[data-theme=tech] .scene::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(90deg,rgba(0,224,200,.05) 0 1px,transparent 1px 56px),
             repeating-linear-gradient(0deg,rgba(0,224,200,.05) 0 1px,transparent 1px 56px)}
.floor{position:absolute;left:0;right:0;bottom:0;height:15%;background:linear-gradient(var(--floor1),var(--floor2));transition:background .6s}
.floor::before{content:'';position:absolute;top:-8px;left:0;right:0;height:8px;background:rgba(255,255,255,.28)}
/* 窗户 */
.window{position:absolute;left:6%;top:15%;width:200px;height:250px;border-radius:14px;border:10px solid var(--frame);
  box-shadow:0 10px 26px var(--shadow);overflow:hidden;transition:border-color .6s}
.sky{position:absolute;inset:0;transition:background .8s}
body[data-theme=day] .sky{background:linear-gradient(#7ec2f2,#cfeaff 70%,#eaf7ff)}
body[data-theme=night] .sky{background:linear-gradient(#0a1230,#1d2f5e 70%,#27406f)}
body[data-theme=sunset] .sky{background:linear-gradient(#5b4a8a,#ff7e6b 55%,#ffc46b)}
body[data-theme=tech] .sky{background:linear-gradient(#04070c,#0a1a24 60%,#0e2f3a)}
.sun{display:none;position:absolute;width:46px;height:46px;border-radius:50%;background:#ffd964;box-shadow:0 0 34px #ffdf7e;right:22px;top:26px}
body[data-theme=day] .sun{display:block}
body[data-theme=sunset] .sun{display:block;background:#ff8c4a;box-shadow:0 0 44px #ff8c4a;top:auto;bottom:30px;right:34px}
.moon{display:none;position:absolute;width:38px;height:38px;border-radius:50%;background:#f2f6ff;
  box-shadow:inset -9px 7px 0 #c9d4ee,0 0 24px rgba(230,240,255,.5);right:24px;top:22px}
body[data-theme=night] .moon{display:block}
.star{display:none;position:absolute;width:3px;height:3px;border-radius:50%;background:#fff;animation:twinkle 2.4s infinite}
body[data-theme=night] .star{display:block}
@keyframes twinkle{50%{opacity:.12}}
.cloud{display:none;position:absolute;height:15px;width:56px;background:#fff;border-radius:20px;opacity:.92;animation:drift linear infinite}
.cloud::before{content:'';position:absolute;width:24px;height:24px;background:#fff;border-radius:50%;top:-11px;left:12px}
body[data-theme=day] .cloud{display:block}
@keyframes drift{from{transform:translateX(-90px)}to{transform:translateX(250px)}}
.c1{top:38px;animation-duration:26s}
.c2{top:92px;animation-duration:38s;animation-delay:-14s;scale:.7}
.tgrid{display:none;position:absolute;inset:0;
  background:linear-gradient(transparent 58%,rgba(0,220,200,.16)),
  repeating-linear-gradient(90deg,rgba(0,220,200,.12) 0 1px,transparent 1px 24px),
  repeating-linear-gradient(0deg,rgba(0,220,200,.12) 0 1px,transparent 1px 24px)}
body[data-theme=tech] .tgrid{display:block}
.bar-v{position:absolute;left:50%;top:0;bottom:0;width:8px;margin-left:-4px;background:var(--frame);z-index:2}
.bar-h{position:absolute;top:50%;left:0;right:0;height:8px;margin-top:-4px;background:var(--frame);z-index:2}
/* 挂画 & 绿植 */
.art{position:absolute;right:7%;top:19%;width:122px;height:88px;border:8px solid var(--frame);border-radius:4px;
  box-shadow:0 8px 18px var(--shadow);transition:.5s;
  background:linear-gradient(135deg,var(--acc) 0%,#ffd166 55%,#1b2a4a 100%)}
body[data-theme=night] .art{filter:brightness(.55)}
.plant{position:absolute;right:9%;bottom:13%;width:130px;height:180px;z-index:3}
.pot{position:absolute;bottom:0;left:50%;transform:translateX(-50%);width:66px;height:52px;
  background:linear-gradient(#d16a3f,#a34a28);border-radius:8px 8px 24px 24px;box-shadow:inset 0 -8px 10px rgba(0,0,0,.2)}
.pot::before{content:'';position:absolute;top:-9px;left:-6px;right:-6px;height:13px;background:#c25c33;border-radius:7px}
.leaf{position:absolute;bottom:52px;left:50%;width:16px;height:88px;margin-left:-8px;transform-origin:bottom center;
  background:linear-gradient(#43975f,#2a6b41);border-radius:50%/60% 60% 42% 42%;
  transform:rotate(var(--r));animation:sway 5s ease-in-out infinite alternate}
@keyframes sway{to{transform:rotate(calc(var(--r) + 4deg))}}
body[data-theme=night] .plant{filter:brightness(.6)}
/* ================= 空调机身 ================= */
.ac{position:absolute;left:50%;top:8%;transform:translateX(-50%);width:min(430px,74%);z-index:5;animation:fadein .9s .2s both}
@keyframes fadein{from{opacity:0}to{opacity:1}}
.ac-body{position:relative;height:118px;border-radius:22px 22px 12px 12px;
  background:linear-gradient(#ffffff,#eef1f4 58%,#d9dee4);
  box-shadow:0 14px 28px var(--shadow),inset 0 -3px 8px rgba(0,0,0,.06),inset 0 2px 3px #fff;transition:.4s}
body[data-theme=night] .ac-body{background:linear-gradient(#f2f4f8,#d6dbe3 58%,#b4bcc7)}
.ac-body::before{content:'';position:absolute;top:13px;left:26px;right:26px;height:5px;border-radius:4px;
  background:repeating-linear-gradient(90deg,#c3cbd4 0 8px,transparent 8px 13px)}
.ac-logo{position:absolute;left:28px;bottom:15px;display:flex;align-items:baseline;gap:7px}
.ac-logo b{font-family:var(--digi);font-size:15px;letter-spacing:2px;color:#5a6572;font-weight:400}
.ac-logo span{font-size:11px;color:#8a95a3}
.ac-tag{position:absolute;right:30px;bottom:16px;width:112px;height:6px;border-radius:4px;background:var(--acc);
  transition:.4s;box-shadow:0 0 10px color-mix(in srgb,var(--acc) 55%,transparent)}
.ac-lights{position:absolute;left:28px;top:34px;display:flex;gap:12px}
.ac-lights i{display:inline-flex;align-items:center;gap:4px;font-size:9px;font-style:normal;color:#9aa4b0;opacity:.22;transition:.35s}
.ac-lights i::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor}
.ac-lights i.on{opacity:1;text-shadow:0 0 8px currentColor}
#ledRun.on{color:var(--led)} #ledEco.on{color:#3ddc84} #ledClean.on{color:#4fc3f7}
.ac-display{position:absolute;right:30px;top:28px;width:112px;height:60px;background:#0d1117;border-radius:10px;overflow:hidden}
.ac-display::after{content:'';position:absolute;inset:0;background:linear-gradient(120deg,rgba(255,255,255,.14),transparent 45%)}
.ac-display .in{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;transition:opacity .4s}
.ac:not(.on) .ac-display .in,.ac.nolight .ac-display .in{opacity:0}
.ac-temp-row{font-family:var(--digi);font-size:27px;line-height:1;color:var(--led);
  text-shadow:0 0 12px color-mix(in srgb,var(--led) 75%,transparent)}
.ac-temp-row i{font-size:13px;font-style:normal}
.ac-sub{margin-top:4px;font-size:10px;letter-spacing:3px;color:var(--led);opacity:.85}
.ac-display.pop .ac-temp-row{animation:tick .3s}
@keyframes tick{40%{transform:scale(1.14)}}
.ac-vent{position:absolute;left:18px;right:18px;bottom:-16px;height:26px;background:#161a20;border-radius:0 0 16px 16px;
  overflow:hidden;perspective:320px;box-shadow:inset 0 5px 9px #000}
.ac-vent::before{content:'';position:absolute;inset:0;background:repeating-linear-gradient(0deg,rgba(255,255,255,.06) 0 2px,transparent 2px 6px)}
.louver{position:absolute;left:6%;right:6%;top:6px;height:9px;border-radius:6px;z-index:2;
  background:linear-gradient(#f4f6f8,#c9d0d8);transform-origin:top center;transform:rotateX(78deg);
  transition:transform .8s cubic-bezier(.34,1.4,.4,1)}
.ac.on .louver{transform:rotateX(38deg)}
.ac.on.swing .louver{animation:lou 3.6s ease-in-out infinite}
@keyframes lou{0%,100%{transform:rotateX(28deg)}50%{transform:rotateX(64deg)}}
.ac-glow{position:absolute;left:8%;right:8%;bottom:-64px;height:74px;pointer-events:none;filter:blur(7px);
  background:radial-gradient(ellipse at top,var(--wind,rgba(120,200,255,.4)),transparent 70%);opacity:0;transition:opacity .7s}
.ac.on .ac-glow{opacity:.75}
/* 除尘粒子 */
.sparkles{position:absolute;inset:-22px;pointer-events:none;opacity:0;transition:.5s}
.ac.clean .sparkles{opacity:1}
.spark{position:absolute;width:5px;height:5px;border-radius:50%;background:#8fd8ff;box-shadow:0 0 9px #8fd8ff;animation:spark 1.8s ease-in-out infinite}
@keyframes spark{0%,100%{transform:scale(.2);opacity:0}50%{transform:scale(1);opacity:1}}
/* 气流 */
.airflow{position:absolute;left:50%;top:calc(8% + 148px);transform:translateX(-50%);width:min(400px,66%);
  height:300px;pointer-events:none;z-index:4;opacity:0;transition:opacity .9s}
.airflow.live{opacity:1}
.stream{position:absolute;top:0;width:3px;height:72px;border-radius:4px;filter:blur(1px);
  background:linear-gradient(var(--wind2,transparent),var(--wind,rgba(120,200,255,.8)));
  left:var(--x);animation:fall var(--t,1.6s) linear var(--d,0s) infinite}
@keyframes fall{
  0%{transform:translateY(-12px) translateX(0) scaleY(.6);opacity:0}
  12%{opacity:.9}
  100%{transform:translateY(280px) translateX(var(--sw,0)) scaleY(1.2);opacity:0}
}
/* 场景 HUD */
.hud{position:absolute;left:18px;bottom:18px;display:flex;gap:8px;flex-wrap:wrap;z-index:6}
.hud .chip{font-size:12px;padding:6px 12px}
/* ================= 遥控器 ================= */
.remote-col{display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:12px;animation:rise .7s .12s both}
.remote{width:252px;background:linear-gradient(160deg,#3a4048,#191d23 60%);border-radius:30px;
  padding:16px 16px 22px;position:relative;
  box-shadow:0 18px 40px var(--shadow),inset 0 1px 0 rgba(255,255,255,.18),inset 0 -6px 14px rgba(0,0,0,.35)}
.remote::before{content:'';position:absolute;top:-7px;left:50%;transform:translateX(-50%);width:56px;height:10px;background:#0c0e11;border-radius:6px 6px 0 0}
.r-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.r-brand{font-family:var(--digi);font-size:11px;letter-spacing:1.5px;color:#9aa3ad}
.power{width:44px;height:44px;border-radius:50%;border:0;cursor:pointer;font-size:17px;color:#b8c0c9;
  background:radial-gradient(circle at 35% 30%,#565e68,#23272d);display:grid;place-items:center;
  box-shadow:0 3px 6px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.2);transition:.25s}
.power:hover{transform:translateY(-1px)}
.power:active{transform:translateY(1px)}
.power.on{color:#fff;background:radial-gradient(circle at 35% 30%,var(--acc),var(--acc2));
  box-shadow:0 0 18px color-mix(in srgb,var(--acc) 60%,transparent),inset 0 1px 0 rgba(255,255,255,.3)}
.lcd{position:relative;overflow:hidden;background:linear-gradient(#dfe9d8,#c6d6c0);color:#223227;
  border:3px solid #12151a;border-radius:12px;padding:10px 12px;min-height:118px;
  box-shadow:inset 0 2px 6px rgba(0,0,0,.28)}
.lcd::after{content:'';position:absolute;inset:0;pointer-events:none;background:linear-gradient(115deg,rgba(255,255,255,.3),transparent 42%)}
.lcd-row{display:flex;justify-content:space-between;align-items:center;font-size:10.5px;font-weight:700;letter-spacing:.5px}
.fbar{display:inline-flex;align-items:flex-end;gap:2px}
.fbar i{display:inline-block;width:3.5px;background:#223227;border-radius:1px;opacity:.14;transition:.2s}
.fbar i:nth-child(1){height:4px}.fbar i:nth-child(2){height:7px}
.fbar i:nth-child(3){height:10px}.fbar i:nth-child(4){height:13px}
.fbar i.on{opacity:1}
.lcd-flags span{opacity:.16;transition:.3s;margin-left:7px}
.lcd-flags span.on{opacity:1}
.lcd-mid{display:flex;justify-content:center;align-items:baseline;padding:4px 0 2px;transition:opacity .3s}
.lcd-temp{font-family:var(--digi);font-size:52px;line-height:1.1;text-shadow:0 1px 0 rgba(255,255,255,.4)}
.lcd-temp small{font-size:15px}
.sb{position:absolute;left:50%;top:53%;transform:translate(-50%,-50%);font-size:13px;font-weight:700;
  letter-spacing:7px;opacity:0;transition:.3s;pointer-events:none}
.lcd.standby .lcd-mid{opacity:.13}
.lcd.standby .sb{opacity:.8}
.lcd-foot{display:flex;justify-content:space-between;font-size:10.5px;font-weight:700}
.r-ctrl{display:grid;grid-template-columns:74px 1fr;gap:12px;margin-top:14px}
.rocker{display:flex;flex-direction:column;gap:8px}
.rk{flex:1;min-height:54px;border-radius:16px;border:0;cursor:pointer;font-size:22px;font-weight:700;color:#cfd6dd;
  background:linear-gradient(#3c434c,#22262c);box-shadow:0 3px 6px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.15);transition:.15s}
.rk:hover{color:#fff}
.rk:active{transform:translateY(2px);box-shadow:0 1px 2px rgba(0,0,0,.5)}
.rk-label{font-size:10px;color:#8b949e;text-align:center;letter-spacing:4px}
.funs{display:grid;grid-template-columns:repeat(3,1fr);gap:11px 6px;align-content:center}
.fn{display:flex;flex-direction:column;align-items:center;gap:5px;border:0;background:none;cursor:pointer;color:#aeb7c0;font-family:var(--body)}
.fn i{width:42px;height:42px;border-radius:50%;display:grid;place-items:center;font-style:normal;
  font-size:12px;font-weight:700;color:#cfd6dd;background:linear-gradient(#3c434c,#22262c);
  box-shadow:0 3px 5px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.14);transition:.18s}
.fn:hover i{transform:translateY(-1px);color:#fff}
.fn:active i{transform:translateY(1px)}
.fn.on i{background:linear-gradient(var(--acc),var(--acc2));color:#fff;
  box-shadow:0 0 14px color-mix(in srgb,var(--acc) 55%,transparent)}
.fn span{font-size:10.5px;letter-spacing:1px}
.hint{font-size:11px;opacity:.55;letter-spacing:1px}
kbd{font-family:var(--digi);border:1px solid var(--line);border-radius:4px;padding:0 5px;font-size:10px}
@keyframes rise{from{opacity:0;transform:translateY(16px)}to{opacity:1;transform:none}}
@media(max-width:920px){
  .main{grid-template-columns:1fr}
  .panel-card{grid-template-columns:1fr}
  .scene{min-height:480px}
}
</style>
</head>
<body data-theme="day" data-brand="gree">
<div class="app">

  <header class="topbar">
    <div class="logo">空调模拟器<small>AIR CONDITIONER SIM</small></div>
    <div class="top-right">
      <div class="chip">室温 <b id="chipRoom">--.-</b> °C</div>
      <button class="chip" id="btnSettings">⚙ 设置 <span class="chev">▾</span></button>
    </div>
  </header>

  <!-- 可折叠设置面板 -->
  <section class="panel" id="panel">
    <div class="panel-in">
      <div class="panel-card">
        <div class="p-group">
          <h3>品牌切换</h3>
          <div class="brands" id="brandList"></div>
        </div>
        <div class="p-group">
          <h3>场景主题</h3>
          <div class="themes" id="themeList"></div>
        </div>
        <div class="p-group">
          <h3>偏好</h3>
          <div class="opts">
            <label class="switch-row">按键提示音<input type="checkbox" id="optSound" checked><span class="track"></span></label>
            <label class="switch-row">气流粒子<input type="checkbox" id="optFlow" checked><span class="track"></span></label>
          </div>
        </div>
      </div>
    </div>
  </section>

  <main class="main">
    <!-- 房间场景 -->
    <section class="scene" id="scene">
      <div class="window">
        <div class="sky" id="sky">
          <div class="sun"></div><div class="moon"></div>
          <div class="cloud c1"></div><div class="cloud c2"></div>
          <div class="tgrid"></div>
        </div>
        <div class="bar-v"></div><div class="bar-h"></div>
      </div>

      <div class="art"></div>

      <!-- 空调机身 -->
      <div class="ac" id="acUnit">
        <div class="ac-body">
          <div class="ac-lights">
            <i id="ledRun">运行</i><i id="ledEco">ECO</i><i id="ledClean">净</i>
          </div>
          <div class="ac-display" id="acDisplay">
            <div class="in">
              <div class="ac-temp-row" id="acTempRow"><span id="acTemp">24</span><i>°C</i></div>
              <div class="ac-sub"><span id="acMode">制冷</span> · <span id="acFanIco">中风</span></div>
            </div>
          </div>
          <div class="ac-logo"><b id="acLogoB">GREE</b><span id="acLogoC">格力</span></div>
          <div class="ac-tag"></div>
          <div class="sparkles" id="sparkles"></div>
        </div>
        <div class="ac-vent"><div class="louver"></div></div>
        <div class="ac-glow"></div>
      </div>
      <div class="airflow" id="airflow"></div>

      <div class="plant">
        <div class="leaf" style="--r:-48deg;height:70px"></div>
        <div class="leaf" style="--r:-24deg;height:84px"></div>
        <div class="leaf" style="--r:0deg;height:94px"></div>
        <div class="leaf" style="--r:24deg;height:84px"></div>
        <div class="leaf" style="--r:48deg;height:70px"></div>
        <div class="pot"></div>
      </div>

      <div class="floor"></div>

      <div class="hud">
        <div class="chip">模式 <b id="chipMode">待机</b></div>
        <div class="chip">目标 <b id="chipTarget">24°</b></div>
        <div class="chip">功率 <b id="chipWatt">0 W</b></div>
        <div class="chip">室外 <b id="chipOut">--</b>°C</div>
      </div>
    </section>

    <!-- 遥控器 -->
    <aside class="remote-col">
      <div class="remote">
        <div class="r-head">
          <div class="r-brand" id="rBrand">GREE · 格力</div>
          <button class="power" id="btnPower" title="开 / 关机">⏻</button>
        </div>

        <div class="lcd standby" id="lcd">
          <div class="lcd-row">
            <span id="lcdMode">制冷</span>
            <span class="fbar" id="fbar"><i></i><i></i><i></i><i></i></span>
            <span class="lcd-flags">
              <span id="flagEco">节能</span><span id="flagClean">除尘</span><span id="flagSwing">扫风</span>
            </span>
          </div>
          <div class="lcd-mid"><span class="lcd-temp" id="lcdTemp">24<small>°C</small></span></div>
          <div class="sb">待 机</div>
          <div class="lcd-foot"><span id="lcdFanTxt">中风</span><span id="lcdClock">--:--</span></div>
        </div>

        <div class="r-ctrl">
          <div class="rocker">
            <button class="rk" id="btnUp" title="升温">+</button>
            <div class="rk-label">温度</div>
            <button class="rk" id="btnDown" title="降温">-</button>
          </div>
          <div class="funs">
            <button class="fn" id="btnMode"><i>模式</i><span>MODE</span></button>
            <button class="fn" id="btnFan"><i>风速</i><span>FAN</span></button>
            <button class="fn" id="btnSwing"><i>扫风</i><span>SWING</span></button>
            <button class="fn" id="btnEco"><i>节能</i><span>ECO</span></button>
            <button class="fn" id="btnClean"><i>除尘</i><span>CLEAN</span></button>
            <button class="fn" id="btnLight"><i>灯光</i><span>LIGHT</span></button>
          </div>
        </div>
      </div>
      <div class="hint"><kbd>↑</kbd><kbd>↓</kbd> 调温 · <kbd>空格</kbd> 开关机</div>
    </aside>
  </main>
</div>

<script>
const $=id=>document.getElementById(id);
/* ---------------- 数据 ---------------- */
const BRANDS={
  gree:{name:'格力',en:'GREE',c:'#0ba45e'},
  midea:{name:'美的',en:'Midea',c:'#1489d6'},
  haier:{name:'海尔',en:'Haier',c:'#2f6bff'},
  mijia:{name:'小米',en:'MIJIA',c:'#ff7a1a'},
  daikin:{name:'大金',en:'DAIKIN',c:'#00b3c8'}
};
const THEMES={
  day:{name:'日间',out:33,pv:'linear-gradient(135deg,#7ec2f2,#eaf7ff 60%,#e8d9c0)'},
  night:{name:'星夜',out:27,pv:'linear-gradient(135deg,#0a1230,#27406f)'},
  sunset:{name:'黄昏',out:30,pv:'linear-gradient(135deg,#5b4a8a,#ff7e6b 55%,#ffc46b)'},
  tech:{name:'曜黑',out:21,pv:'linear-gradient(135deg,#04070c,#0e2f3a)'}
};
const MODES=['auto','cool','dry','fan','heat'];
const MODE_TXT={auto:'自动',cool:'制冷',dry:'除湿',fan:'送风',heat:'制热'};
const FANS=['静音','低风','中风','强风'];
const WIND={
  cool:['rgba(96,190,255,.85)','rgba(96,190,255,0)'],
  heat:['rgba(255,150,70,.85)','rgba(255,150,70,0)'],
  dry:['rgba(150,225,255,.6)','rgba(150,225,255,0)'],
  fan:['rgba(205,220,235,.55)','rgba(205,220,235,0)'],
  auto:['rgba(130,235,200,.75)','rgba(130,235,200,0)']
};
const WATT={auto:620,cool:820,dry:480,fan:55,heat:980};
const state={power:false,temp:24,mode:'cool',fan:2,swing:false,eco:false,clean:false,
             light:true,brand:'gree',theme:'day',sound:true,flow:true,room:29.4};
/* ---------------- 提示音 ---------------- */
let AC;
function beep(f=2200,d=.055,g=.05){
  if(!state.sound)return;
  try{
    AC=AC||new (window.AudioContext||window.webkitAudioContext)();
    if(AC.state==='suspended')AC.resume();
    const o=AC.createOscillator(),ga=AC.createGain();
    o.type='square';o.frequency.value=f;
    ga.gain.setValueAtTime(g,AC.currentTime);
    ga.gain.exponentialRampToValueAtTime(.0001,AC.currentTime+d);
    o.connect(ga).connect(AC.destination);o.start();o.stop(AC.currentTime+d);
  }catch(e){}
}
/* ---------------- 生成环境元素 ---------------- */
const sky=$('sky');
for(let i=0;i<16;i++){
  const s=document.createElement('i');s.className='star';
  s.style.left=Math.random()*94+'%';s.style.top=Math.random()*70+'%';
  s.style.animationDelay=(Math.random()*2.4)+'s';sky.appendChild(s);
}
const af=$('airflow');
for(let i=0;i<14;i++){
  const s=document.createElement('div');s.className='stream';
  s.style.setProperty('--x',(4+Math.random()*90).toFixed(1)+'%');
  s.style.setProperty('--d',(Math.random()*2).toFixed(2)+'s');
  s.style.setProperty('--sw',(Math.random()*44-22).toFixed(0)+'px');
  af.appendChild(s);
}
const sp=$('sparkles');
[[6,12],[88,6],[45,-6],[12,88],[80,92],[55,104],[-4,55],[98,50]].forEach((p,i)=>{
  const d=document.createElement('div');d.className='spark';
  d.style.left=p[0]+'%';d.style.top=p[1]+'%';d.style.animationDelay=(i*.22)+'s';sp.appendChild(d);
});
/* ---------------- 设置面板内容 ---------------- */
const brandList=$('brandList');
Object.entries(BRANDS).forEach(([id,b])=>{
  const el=document.createElement('button');el.className='b-btn';el.style.setProperty('--bc',b.c);
  el.innerHTML=`<span class="dot"></span><span>${b.name}</span>`;
  el.onclick=()=>{state.brand=id;beep(1800,.05);render();};
  brandList.appendChild(el);
});
const themeList=$('themeList');
Object.entries(THEMES).forEach(([id,t])=>{
  const el=document.createElement('button');el.className='t-btn';
  el.innerHTML=`<div class="sw" style="--pv:${t.pv}"></div><span>${t.name}</span>`;
  el.onclick=()=>{state.theme=id;beep(1800,.05);render();};
  themeList.appendChild(el);
});
/* ---------------- 渲染 ---------------- */
function watts(){
  let w=WATT[state.mode]*(0.72+state.fan*0.14);
  if(state.eco)w*=.6; if(state.clean)w*=1.12; return w;
}
function render(){
  document.body.dataset.theme=state.theme;
  document.body.dataset.brand=state.brand;
  const b=BRANDS[state.brand];
  $('acLogoB').textContent=b.en;$('acLogoC').textContent=b.name;
  $('rBrand').textContent=b.en+' · '+b.name;
  [...brandList.children].forEach((el,i)=>el.classList.toggle('on',Object.keys(BRANDS)[i]===state.brand));
  [...themeList.children].forEach((el,i)=>el.classList.toggle('on',Object.keys(THEMES)[i]===state.theme));
  // 机身
  const ac=$('acUnit');
  ac.classList.toggle('on',state.power);
  ac.classList.toggle('swing',state.swing&&state.power);
  ac.classList.toggle('clean',state.clean&&state.power);
  ac.classList.toggle('nolight',!state.light);
  $('acTemp').textContent=state.temp;
  $('acMode').textContent=MODE_TXT[state.mode];
  $('acFanIco').textContent=FANS[state.fan];
  $('ledRun').classList.toggle('on',state.power);
  $('ledEco').classList.toggle('on',state.eco&&state.power);
  $('ledClean').classList.toggle('on',state.clean&&state.power);
  // 气流
  af.classList.toggle('live',state.power&&state.flow);
  const sc=$('scene'),w=WIND[state.mode];
  sc.style.setProperty('--wind',w[0]);sc.style.setProperty('--wind2',w[1]);
  const dur=[2.4,1.9,1.4,1.0][state.fan]*(state.eco?1.35:1);
  af.querySelectorAll('.stream').forEach(s=>s.style.setProperty('--t',dur.toFixed(2)+'s'));
  // 遥控 LCD
  $('lcd').classList.toggle('standby',!state.power);
  $('lcdTemp').innerHTML=state.temp+'<small>°C</small>';
  $('lcdMode').textContent=MODE_TXT[state.mode];
  $('lcdFanTxt').textContent=FANS[state.fan];
  [...$('fbar').children].forEach((bar,i)=>bar.classList.toggle('on',i<=state.fan));
  $('flagEco').classList.toggle('on',state.eco);
  $('flagClean').classList.toggle('on',state.clean);
  $('flagSwing').classList.toggle('on',state.swing);
  // 按键状态
  $('btnPower').classList.toggle('on',state.power);
  $('btnSwing').parentElement.classList.toggle('on',state.swing);
  $('btnEco').parentElement.classList.toggle('on',state.eco);
  $('btnClean').parentElement.classList.toggle('on',state.clean);
  $('btnLight').parentElement.classList.toggle('on',state.light);
  // HUD
  $('chipRoom').textContent=state.room.toFixed(1);
  $('chipOut').textContent=THEMES[state.theme].out;
  $('chipMode').textContent=state.power?MODE_TXT[state.mode]:'待机';
  $('chipTarget').textContent=state.temp+'°';
  $('chipWatt').textContent=state.power?Math.round(watts())+' W':'0 W';
}
/* ---------------- 操作 ---------------- */
function pop(){const d=$('acDisplay');d.classList.remove('pop');void d.offsetWidth;d.classList.add('pop');}
function togglePower(){
  state.power=!state.power;
  beep(2400,.07,.06);setTimeout(()=>beep(2400,.07,.06),120);
  render();
}
function bump(d){
  const t=state.temp+d;
  if(t<16||t>30){beep(220,.09);return;}
  state.temp=t;beep();pop();render();
}
$('btnPower').onclick=togglePower;
$('btnUp').onclick=()=>bump(1);
$('btnDown').onclick=()=>bump(-1);
$('btnMode').onclick=()=>{state.mode=MODES[(MODES.indexOf(state.mode)+1)%MODES.length];beep();render();};
$('btnFan').onclick=()=>{state.fan=(state.fan+1)%4;beep();render();};
$('btnSwing').onclick=()=>{state.swing=!state.swing;beep();render();};
$('btnEco').onclick=()=>{state.eco=!state.eco;beep();render();};
$('btnClean').onclick=()=>{state.clean=!state.clean;beep();render();};
$('btnLight').onclick=()=>{state.light=!state.light;beep();render();};
/* 设置面板折叠 */
$('btnSettings').onclick=()=>{
  $('panel').classList.toggle('open');
  $('btnSettings').classList.toggle('open');
  beep(1600,.04);
};
$('optSound').onchange=e=>{state.sound=e.target.checked;};
$('optFlow').onchange=e=>{state.flow=e.target.checked;render();};
/* 键盘 */
addEventListener('keydown',e=>{
  if(e.code==='ArrowUp'){bump(1);e.preventDefault();}
  else if(e.code==='ArrowDown'){bump(-1);e.preventDefault();}
  else if(e.code==='Space'&&e.target.tagName!=='BUTTON'){togglePower();e.preventDefault();}
});
/* 室温仿真 */
setInterval(()=>{
  const out=THEMES[state.theme].out;
  if(state.power&&state.mode!=='fan'){
    const diff=state.temp-state.room;
    const eff=(state.mode==='dry'?0.7:1)*(state.eco?0.65:1)*(0.6+state.fan*0.18);
    state.room+=Math.max(-.5,Math.min(.5,diff*0.045*eff));
  }else if(state.power){
    state.room+=(out-state.room)*0.012;
  }else{
    state.room+=(out-state.room)*0.02;
  }
  $('chipRoom').textContent=state.room.toFixed(1);
  $('chipWatt').textContent=state.power?Math.round(watts())+' W':'0 W';
},1000);
/* LCD 时钟 */
setInterval(()=>{
  const d=new Date();
  $('lcdClock').textContent=String(d.getHours()).padStart(2,'0')+':'+String(d.getMinutes()).padStart(2,'0');
},1000);
render();
</script>
</body>
</html>
        
编辑器加载中
预览
控制台