diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2d9bb44
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+# 备份与临时文件,不进版本库
+__bak_pre_20260722/
+*.bak
+*.bak2
+*.backup
diff --git a/assets/bg/world_bg_keyart_16x9.png b/assets/bg/world_bg_keyart_16x9.png
new file mode 100644
index 0000000..95c1070
Binary files /dev/null and b/assets/bg/world_bg_keyart_16x9.png differ
diff --git a/assets/bg/world_bg_keyart_16x9_clean.png b/assets/bg/world_bg_keyart_16x9_clean.png
new file mode 100644
index 0000000..5c9bde1
Binary files /dev/null and b/assets/bg/world_bg_keyart_16x9_clean.png differ
diff --git a/assets/bg_core.jpg b/assets/bg_core.jpg
new file mode 100644
index 0000000..d0fe1aa
Binary files /dev/null and b/assets/bg_core.jpg differ
diff --git a/assets/bg_earth.jpg b/assets/bg_earth.jpg
new file mode 100644
index 0000000..9491ea8
Binary files /dev/null and b/assets/bg_earth.jpg differ
diff --git a/assets/bg_sky.jpg b/assets/bg_sky.jpg
new file mode 100644
index 0000000..3af96ca
Binary files /dev/null and b/assets/bg_sky.jpg differ
diff --git a/assets/bg_star.jpg b/assets/bg_star.jpg
new file mode 100644
index 0000000..d52e504
Binary files /dev/null and b/assets/bg_star.jpg differ
diff --git a/assets/bg_under.jpg b/assets/bg_under.jpg
new file mode 100644
index 0000000..721272e
Binary files /dev/null and b/assets/bg_under.jpg differ
diff --git a/assets/game-api.js b/assets/game-api.js
new file mode 100644
index 0000000..d114327
--- /dev/null
+++ b/assets/game-api.js
@@ -0,0 +1,42 @@
+// 宇森游戏 · 前端与 Odoo 通信层
+// 所有接口同源(yt.pengyuthon.cn),由 nginx 代理 /game/* 到 Odoo(game 库)。
+// 关键点:Odoo 通过 URL 上的 ?db=game 选定数据库(与 game.conf 的 /web/login?db=game 一致),
+// 否则请求到达时未选中库,控制器路由找不到 → 404。因此所有调用都带 ?db=game。
+// 登录态通过 Odoo session cookie 保持,fetch 带 credentials:'same-origin'。
+
+const API = {
+ async me() {
+ return (await fetch('/game/api/me?db=game', { credentials: 'same-origin' })).json();
+ },
+ async login(login, password) {
+ return (await fetch('/game/api/login?db=game', {
+ method: 'POST', credentials: 'same-origin',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ login, password }),
+ })).json();
+ },
+ async register(payload) {
+ return (await fetch('/game/api/register?db=game', {
+ method: 'POST', credentials: 'same-origin',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(payload),
+ })).json();
+ },
+ async logout() {
+ return (await fetch('/game/api/logout?db=game', {
+ method: 'POST', credentials: 'same-origin',
+ })).json();
+ },
+ async codex() {
+ return (await fetch('/game/api/codex?db=game', { credentials: 'same-origin' })).json();
+ },
+ async rules() {
+ return (await fetch('/game/api/rules?db=game', { credentials: 'same-origin' })).json();
+ },
+ async threads() {
+ return (await fetch('/game/api/threads?db=game', { credentials: 'same-origin' })).json();
+ },
+ async announcements() {
+ return (await fetch('/game/api/announcements?db=game', { credentials: 'same-origin' })).json();
+ },
+};
diff --git a/assets/site-app.js b/assets/site-app.js
new file mode 100644
index 0000000..2fc071b
--- /dev/null
+++ b/assets/site-app.js
@@ -0,0 +1,69 @@
+// 宇森官网 · 公开页数据打通(图鉴/规则/论坛/公告 从 Odoo 取数)
+// 依赖 assets/game-api.js
+
+// ---------- 规则 ----------
+async function loadRules(){
+ const el = document.querySelector('#rules .rules-scroll');
+ if (!el) return;
+ try {
+ const d = await API.rules();
+ const groups = (d && d.groups) || [];
+ if (!groups.length){ el.innerHTML = '
暂无规则数据
'; return; }
+ el.innerHTML = groups.map(g => {
+ const rows = (g.items || []).map(it => {
+ const lvl = (it.level != null) ? ('Lv.' + it.level) : (g.key === 'world' ? '阶段' : '');
+ return `${lvl}${it.name}${it.desc || ''}
`;
+ }).join('');
+ return ``;
+ }).join('');
+ } catch (e) { /* 保留静态兜底内容 */ }
+}
+
+// ---------- 论坛 ----------
+async function loadForum(){
+ const threadsEl = document.getElementById('threads');
+ const catsEl = document.querySelector('#forum .f-cats');
+ if (!threadsEl) return;
+ try {
+ const list = await API.threads();
+ if (!list || !list.length){ threadsEl.innerHTML = '暂无主题
'; return; }
+ // 分类筛选
+ const cats = [];
+ list.forEach(t => { if (t.category && cats.indexOf(t.category) < 0) cats.push(t.category); });
+ if (catsEl){
+ catsEl.innerHTML = `全部
` +
+ cats.map(c => `${c}
`).join('');
+ catsEl.querySelectorAll('.ch').forEach(b => b.addEventListener('click', () => {
+ catsEl.querySelectorAll('.ch').forEach(x => x.classList.remove('active'));
+ b.classList.add('active');
+ const c = b.dataset.fcat;
+ threadsEl.querySelectorAll('.th').forEach(t => { t.style.display = (c === 'all' || t.dataset.fcat === c) ? '' : 'none'; });
+ }));
+ }
+ threadsEl.innerHTML = list.map(t =>
+ `` +
+ (t.pinned ? `置顶` : '') +
+ `${t.name}` +
+ `${(t.replies || []).length} 回复 · ${t.author_name || '匿名'}
`
+ ).join('');
+ } catch (e) { /* 保留静态兜底内容 */ }
+}
+
+// ---------- 公告 ----------
+async function loadAnnounce(){
+ const el = document.querySelector('#announce .notes');
+ if (!el) return;
+ try {
+ const list = await API.announcements();
+ if (!list || !list.length){ el.innerHTML = ''; return; }
+ el.innerHTML = list.map(n =>
+ `${n.date}
${n.body_html || ''}
`
+ ).join('');
+ } catch (e) { /* 保留静态兜底内容 */ }
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ loadRules();
+ loadForum();
+ loadAnnounce();
+});
diff --git a/assets/terrain/desert_1.png b/assets/terrain/desert_1.png
new file mode 100644
index 0000000..db25e39
Binary files /dev/null and b/assets/terrain/desert_1.png differ
diff --git a/assets/terrain/desert_2.png b/assets/terrain/desert_2.png
new file mode 100644
index 0000000..78118f6
Binary files /dev/null and b/assets/terrain/desert_2.png differ
diff --git a/assets/terrain/desert_3.png b/assets/terrain/desert_3.png
new file mode 100644
index 0000000..5aa1a7b
Binary files /dev/null and b/assets/terrain/desert_3.png differ
diff --git a/assets/terrain/desert_4.png b/assets/terrain/desert_4.png
new file mode 100644
index 0000000..28b3eab
Binary files /dev/null and b/assets/terrain/desert_4.png differ
diff --git a/assets/terrain/desert_5.png b/assets/terrain/desert_5.png
new file mode 100644
index 0000000..684adcd
Binary files /dev/null and b/assets/terrain/desert_5.png differ
diff --git a/assets/terrain/desert_6.png b/assets/terrain/desert_6.png
new file mode 100644
index 0000000..cf85dcb
Binary files /dev/null and b/assets/terrain/desert_6.png differ
diff --git a/assets/terrain/desert_7.png b/assets/terrain/desert_7.png
new file mode 100644
index 0000000..9ac324d
Binary files /dev/null and b/assets/terrain/desert_7.png differ
diff --git a/assets/terrain/forest_1.png b/assets/terrain/forest_1.png
new file mode 100644
index 0000000..fb06244
Binary files /dev/null and b/assets/terrain/forest_1.png differ
diff --git a/assets/terrain/forest_2.png b/assets/terrain/forest_2.png
new file mode 100644
index 0000000..ee3d663
Binary files /dev/null and b/assets/terrain/forest_2.png differ
diff --git a/assets/terrain/forest_3.png b/assets/terrain/forest_3.png
new file mode 100644
index 0000000..0e1c712
Binary files /dev/null and b/assets/terrain/forest_3.png differ
diff --git a/assets/terrain/forest_5.png b/assets/terrain/forest_5.png
new file mode 100644
index 0000000..5922e6f
Binary files /dev/null and b/assets/terrain/forest_5.png differ
diff --git a/assets/terrain/forest_6.png b/assets/terrain/forest_6.png
new file mode 100644
index 0000000..11fd2b0
Binary files /dev/null and b/assets/terrain/forest_6.png differ
diff --git a/assets/terrain/forest_7.png b/assets/terrain/forest_7.png
new file mode 100644
index 0000000..91ee4a7
Binary files /dev/null and b/assets/terrain/forest_7.png differ
diff --git a/assets/terrain/forest_8.png b/assets/terrain/forest_8.png
new file mode 100644
index 0000000..d22b8f5
Binary files /dev/null and b/assets/terrain/forest_8.png differ
diff --git a/assets/terrain/manifest.json b/assets/terrain/manifest.json
new file mode 100644
index 0000000..f0bb6d8
--- /dev/null
+++ b/assets/terrain/manifest.json
@@ -0,0 +1,60 @@
+{
+ "desert": [
+ "desert_1.png",
+ "desert_2.png",
+ "desert_3.png",
+ "desert_4.png",
+ "desert_5.png",
+ "desert_6.png",
+ "desert_7.png"
+ ],
+ "snow": [
+ "snow_1.png",
+ "snow_2.png",
+ "snow_3.png",
+ "snow_4.png",
+ "snow_5.png",
+ "snow_6.png",
+ "snow_8.png"
+ ],
+ "forest": [
+ "forest_1.png",
+ "forest_2.png",
+ "forest_3.png",
+ "forest_5.png",
+ "forest_6.png",
+ "forest_7.png",
+ "forest_8.png"
+ ],
+ "plain": [
+ "plain_1.png",
+ "plain_2.png",
+ "plain_3.png",
+ "plain_4.png",
+ "plain_5.png",
+ "plain_6.png",
+ "plain_7.png",
+ "plain_8.png"
+ ],
+ "mountain": [
+ "mountain_1.png",
+ "mountain_2.png",
+ "mountain_3.png",
+ "mountain_4.png",
+ "mountain_5.png",
+ "mountain_6.png",
+ "mountain_7.png",
+ "mountain_8.png"
+ ],
+ "water": [
+ "water_1.png",
+ "water_2.png",
+ "water_3.png",
+ "water_4.png",
+ "water_5.png",
+ "water_6.png",
+ "water_7.png",
+ "water_8.png",
+ "water_9.png"
+ ]
+}
\ No newline at end of file
diff --git a/assets/terrain/mountain_1.png b/assets/terrain/mountain_1.png
new file mode 100644
index 0000000..34a5081
Binary files /dev/null and b/assets/terrain/mountain_1.png differ
diff --git a/assets/terrain/mountain_2.png b/assets/terrain/mountain_2.png
new file mode 100644
index 0000000..a94e37d
Binary files /dev/null and b/assets/terrain/mountain_2.png differ
diff --git a/assets/terrain/mountain_3.png b/assets/terrain/mountain_3.png
new file mode 100644
index 0000000..e0771ee
Binary files /dev/null and b/assets/terrain/mountain_3.png differ
diff --git a/assets/terrain/mountain_4.png b/assets/terrain/mountain_4.png
new file mode 100644
index 0000000..ccf759f
Binary files /dev/null and b/assets/terrain/mountain_4.png differ
diff --git a/assets/terrain/mountain_5.png b/assets/terrain/mountain_5.png
new file mode 100644
index 0000000..1f3b263
Binary files /dev/null and b/assets/terrain/mountain_5.png differ
diff --git a/assets/terrain/mountain_6.png b/assets/terrain/mountain_6.png
new file mode 100644
index 0000000..4fc66b4
Binary files /dev/null and b/assets/terrain/mountain_6.png differ
diff --git a/assets/terrain/mountain_7.png b/assets/terrain/mountain_7.png
new file mode 100644
index 0000000..9c32c81
Binary files /dev/null and b/assets/terrain/mountain_7.png differ
diff --git a/assets/terrain/mountain_8.png b/assets/terrain/mountain_8.png
new file mode 100644
index 0000000..67b2df4
Binary files /dev/null and b/assets/terrain/mountain_8.png differ
diff --git a/assets/terrain/plain_1.png b/assets/terrain/plain_1.png
new file mode 100644
index 0000000..6c13838
Binary files /dev/null and b/assets/terrain/plain_1.png differ
diff --git a/assets/terrain/plain_2.png b/assets/terrain/plain_2.png
new file mode 100644
index 0000000..c06e084
Binary files /dev/null and b/assets/terrain/plain_2.png differ
diff --git a/assets/terrain/plain_3.png b/assets/terrain/plain_3.png
new file mode 100644
index 0000000..97d1ee7
Binary files /dev/null and b/assets/terrain/plain_3.png differ
diff --git a/assets/terrain/plain_4.png b/assets/terrain/plain_4.png
new file mode 100644
index 0000000..aa28fb9
Binary files /dev/null and b/assets/terrain/plain_4.png differ
diff --git a/assets/terrain/plain_5.png b/assets/terrain/plain_5.png
new file mode 100644
index 0000000..a7ce38a
Binary files /dev/null and b/assets/terrain/plain_5.png differ
diff --git a/assets/terrain/plain_6.png b/assets/terrain/plain_6.png
new file mode 100644
index 0000000..e238490
Binary files /dev/null and b/assets/terrain/plain_6.png differ
diff --git a/assets/terrain/plain_7.png b/assets/terrain/plain_7.png
new file mode 100644
index 0000000..dda809e
Binary files /dev/null and b/assets/terrain/plain_7.png differ
diff --git a/assets/terrain/plain_8.png b/assets/terrain/plain_8.png
new file mode 100644
index 0000000..523f286
Binary files /dev/null and b/assets/terrain/plain_8.png differ
diff --git a/assets/terrain/snow_1.png b/assets/terrain/snow_1.png
new file mode 100644
index 0000000..7f79f0f
Binary files /dev/null and b/assets/terrain/snow_1.png differ
diff --git a/assets/terrain/snow_2.png b/assets/terrain/snow_2.png
new file mode 100644
index 0000000..2942371
Binary files /dev/null and b/assets/terrain/snow_2.png differ
diff --git a/assets/terrain/snow_3.png b/assets/terrain/snow_3.png
new file mode 100644
index 0000000..d147f09
Binary files /dev/null and b/assets/terrain/snow_3.png differ
diff --git a/assets/terrain/snow_4.png b/assets/terrain/snow_4.png
new file mode 100644
index 0000000..98919d6
Binary files /dev/null and b/assets/terrain/snow_4.png differ
diff --git a/assets/terrain/snow_5.png b/assets/terrain/snow_5.png
new file mode 100644
index 0000000..3014116
Binary files /dev/null and b/assets/terrain/snow_5.png differ
diff --git a/assets/terrain/snow_6.png b/assets/terrain/snow_6.png
new file mode 100644
index 0000000..3346976
Binary files /dev/null and b/assets/terrain/snow_6.png differ
diff --git a/assets/terrain/snow_8.png b/assets/terrain/snow_8.png
new file mode 100644
index 0000000..258cc1b
Binary files /dev/null and b/assets/terrain/snow_8.png differ
diff --git a/assets/terrain/water_1.png b/assets/terrain/water_1.png
new file mode 100644
index 0000000..c27795f
Binary files /dev/null and b/assets/terrain/water_1.png differ
diff --git a/assets/terrain/water_2.png b/assets/terrain/water_2.png
new file mode 100644
index 0000000..0443ae3
Binary files /dev/null and b/assets/terrain/water_2.png differ
diff --git a/assets/terrain/water_3.png b/assets/terrain/water_3.png
new file mode 100644
index 0000000..fba1d14
Binary files /dev/null and b/assets/terrain/water_3.png differ
diff --git a/assets/terrain/water_4.png b/assets/terrain/water_4.png
new file mode 100644
index 0000000..815ff61
Binary files /dev/null and b/assets/terrain/water_4.png differ
diff --git a/assets/terrain/water_5.png b/assets/terrain/water_5.png
new file mode 100644
index 0000000..9519e20
Binary files /dev/null and b/assets/terrain/water_5.png differ
diff --git a/assets/terrain/water_6.png b/assets/terrain/water_6.png
new file mode 100644
index 0000000..df3a064
Binary files /dev/null and b/assets/terrain/water_6.png differ
diff --git a/assets/terrain/water_7.png b/assets/terrain/water_7.png
new file mode 100644
index 0000000..58b0a8d
Binary files /dev/null and b/assets/terrain/water_7.png differ
diff --git a/assets/terrain/water_8.png b/assets/terrain/water_8.png
new file mode 100644
index 0000000..5f2cd60
Binary files /dev/null and b/assets/terrain/water_8.png differ
diff --git a/assets/terrain/water_9.png b/assets/terrain/water_9.png
new file mode 100644
index 0000000..86629ae
Binary files /dev/null and b/assets/terrain/water_9.png differ
diff --git a/assets/ui/logo_planet.png b/assets/ui/logo_planet.png
new file mode 100644
index 0000000..4026f98
Binary files /dev/null and b/assets/ui/logo_planet.png differ
diff --git a/assets/ui/logo_planet_256.png b/assets/ui/logo_planet_256.png
new file mode 100644
index 0000000..4561b42
Binary files /dev/null and b/assets/ui/logo_planet_256.png differ
diff --git a/assets/ui/logo_planet_48.png b/assets/ui/logo_planet_48.png
new file mode 100644
index 0000000..8cbc5ff
Binary files /dev/null and b/assets/ui/logo_planet_48.png differ
diff --git a/assets/world-app.js b/assets/world-app.js
new file mode 100644
index 0000000..753454c
--- /dev/null
+++ b/assets/world-app.js
@@ -0,0 +1,164 @@
+// 宇森 · 世界内面板逻辑(图鉴 / 规则 / 论坛 / 公告)
+// 依赖 assets/game-api.js(提供 API)
+
+// ---------- 登录态守卫 ----------
+// TEMP: 本地临时默认放行,跳过 Odoo 登录校验;打通后端后删除此分支并恢复下面逻辑
+const TEMP_SKIP_AUTH = true;
+(async () => {
+ if (TEMP_SKIP_AUTH) {
+ const u = document.getElementById('userName');
+ if (u) u.textContent = '园丁';
+ return;
+ }
+ try {
+ const me = await API.me();
+ if (!me.uid) { location.href = 'login.html?next=world.html'; return; }
+ const u = document.getElementById('userName');
+ if (u) u.textContent = me.name || me.login;
+ } catch (e) {
+ location.href = 'login.html';
+ }
+})();
+
+// ---------- 退出 ----------
+const logoutBtn = document.getElementById('logoutBtn');
+if (logoutBtn) logoutBtn.addEventListener('click', async () => {
+ await API.logout();
+ location.href = 'index.html';
+});
+
+// ---------- 面板控制 ----------
+const panel = document.getElementById('dataPanel');
+const dpTitle = document.getElementById('dpTitle');
+const dpBody = document.getElementById('dpBody');
+const dpClose = document.getElementById('dpClose');
+if (dpClose) dpClose.addEventListener('click', () => panel.classList.remove('open'));
+
+async function openPanel(kind) {
+ if (!panel) return;
+ panel.classList.add('open');
+ dpBody.innerHTML = '加载中…
';
+ try {
+ if (kind === 'codex') { dpTitle.textContent = '图鉴'; renderCodex(await API.codex()); }
+ else if (kind === 'rules') { dpTitle.textContent = '规则'; renderRules(await API.rules()); }
+ else if (kind === 'forum') { dpTitle.textContent = '论坛'; renderForum(await API.threads()); }
+ else if (kind === 'announce') { dpTitle.textContent = '公告'; renderAnnounce(await API.announcements()); }
+ } catch (e) {
+ dpBody.innerHTML = '加载失败,请稍后重试
';
+ }
+}
+
+document.querySelectorAll('.world-nav button[data-panel]').forEach(b => {
+ b.addEventListener('click', () => openPanel(b.dataset.panel));
+});
+
+// ---------- 程序化矢量缩略图(零 AI 生图,不消耗积分) ----------
+function hashStr(s){let h=2166136261;for(let i=0;i>>0;}
+function rng(seed){let s=seed>>>0;return function(){s=(Math.imul(s,1664525)+1013904223)>>>0;return s/4294967296;};}
+const TIERCOL={'普通':'#9aa6c4','精良':'#5fd38a','稀有':'#4cc9f0','史诗':'#c77dff','传说':'#e7b85c'};
+function starPts(cx,cy,spikes,outer,inner){let pts=[],rot=-Math.PI/2;for(let i=0;i`;if(v===0){x+=``;}else if(v===1){x+=``;}else{x+=``;}x+=``;return x;}
+function shBuild(r,s){let x=``;x+=``;for(let i=0;i<3;i++)x+=``;return x;}
+function shElement(r,s){const sides=3+Math.floor(r()*6);let x=``;x+=``;return x;}
+function shPersona(r,s){let x=``;x+=``;x+=``;return x;}
+function shTalent(r,s){const sp=4+Math.floor(r()*4);let x=``;x+=``;return x;}
+function shRelic(r,s){let x=``;x+=``;return x;}
+function shEquip(sub,s){switch(sub){case 'head':return ``;case 'hand':{let x=``;for(let i=0;i<3;i++)x+=``;return x;}case 'chest':return ``;case 'pants':return ``;case 'shoes':return ``;case 'ring':return ``;case 'neck':return ``;case 'treasure':return ``;default:return ``;}}
+function shEvent(r,s){let x=``;x+=``;return x;}
+function shapeFor(cat,sub,r,s){switch(cat){case 'race':return shRace(r,s);case 'build':return shBuild(r,s);case 'element':return shElement(r,s);case 'persona':return shPersona(r,s);case 'talent':return shTalent(r,s);case 'relic':return shRelic(r,s);case 'equip':return shEquip(sub,s);case 'event':return shEvent(r,s);default:return ``;}}
+function thumbSVG(it){
+ const seed=hashStr(it.cat+it.sub+it.name);const r=rng(seed);const h=Math.floor(r()*360);const h2=(h+40)%360;
+ const tcol=TIERCOL[it.tier]||'#9aa6c4';const shape=shapeFor(it.cat,it.sub,r,seed);
+ return ``;
+}
+
+// ---------- 渲染:图鉴(分类 → 子级 → 条目) ----------
+function renderCodex(data){
+ const groups = (data && data.groups) || [];
+ if (!groups.length){ dpBody.innerHTML = '暂无图鉴数据
'; return; }
+ let html = '';
+ groups.forEach(g => {
+ html += `${g.label}
`;
+ (g.subs || []).forEach(sub => {
+ if (sub.name && sub.name !== '其他') html += `
${sub.name}
`;
+ html += '
';
+ sub.items.forEach(it => {
+ const imgTag = it.image
+ ? `

`
+ : '';
+ const fallback = `
${thumbSVG(it)}
`;
+ html += `
`+
+ `
${imgTag || fallback}
`+
+ `
${it.name}
`+
+ `
${it.sub||''}${it.tier||''}
`+
+ `
${it.desc||''}
`;
+ });
+ html += '
';
+ });
+ html += '
';
+ });
+ dpBody.innerHTML = html;
+ // 处理有 image 但加载失败的:替换为程序化 SVG
+ dpBody.querySelectorAll('img.dp-thumb-img').forEach(img => {
+ img.addEventListener('error', () => {
+ const svg = thumbSVG({cat:img.dataset.cat, sub:img.dataset.sub, name:img.dataset.name, tier:img.dataset.tier});
+ const div = document.createElement('div'); div.className='dp-thumb-svg'; div.innerHTML = svg;
+ img.replaceWith(div);
+ });
+ });
+}
+
+// ---------- 渲染:规则(按类别分组) ----------
+function renderRules(data){
+ const groups = (data && data.groups) || [];
+ if (!groups.length){ dpBody.innerHTML = '暂无规则数据
'; return; }
+ let html = '';
+ groups.forEach(g => {
+ html += `${g.label}
`;
+ (g.items || []).forEach(it => {
+ const lvl = (it.level!=null) ? ('Lv.'+it.level) : '';
+ html += `
${lvl}${it.name}${it.desc||''}
`;
+ });
+ html += '
';
+ });
+ dpBody.innerHTML = html;
+}
+
+// ---------- 渲染:论坛 ----------
+function renderForum(threads){
+ threads = threads || [];
+ if (!threads.length){ dpBody.innerHTML = '暂无主题
'; return; }
+ let html = '';
+ threads.forEach(t => {
+ const replies = (t.replies || []).map(p =>
+ `
${p.author_name||'匿名'}${p.create_date}
${p.body_html||''}
`
+ ).join('');
+ html += `
`+
+ `
${t.category_label||''}`+
+ (t.pinned?`置顶`:'')+`${t.name}`+
+ `${t.author_name||''}
`+
+ `
${t.body_html||''}
`+
+ `
${replies}
`;
+ });
+ html += '
';
+ dpBody.innerHTML = html;
+}
+
+// ---------- 渲染:公告 ----------
+function renderAnnounce(list){
+ list = list || [];
+ if (!list.length){ dpBody.innerHTML = '暂无公告
'; return; }
+ let html = '';
+ list.forEach(n => {
+ const pri = n.priority==='urgent' ? 'urgent' : (n.priority==='important' ? 'imp' : '');
+ html += `
${n.date}
`+
+ `
${n.body_html||''}
`;
+ });
+ html += '
';
+ dpBody.innerHTML = html;
+}
diff --git a/assets/world_core.mp4 b/assets/world_core.mp4
new file mode 100644
index 0000000..5db0e97
Binary files /dev/null and b/assets/world_core.mp4 differ
diff --git a/assets/world_earth.mp4 b/assets/world_earth.mp4
new file mode 100644
index 0000000..6ff81a9
Binary files /dev/null and b/assets/world_earth.mp4 differ
diff --git a/assets/world_sky.mp4 b/assets/world_sky.mp4
new file mode 100644
index 0000000..dd81fc9
Binary files /dev/null and b/assets/world_sky.mp4 differ
diff --git a/assets/world_star.mp4 b/assets/world_star.mp4
new file mode 100644
index 0000000..8441d06
Binary files /dev/null and b/assets/world_star.mp4 differ
diff --git a/assets/world_under.mp4 b/assets/world_under.mp4
new file mode 100644
index 0000000..5f3bd87
Binary files /dev/null and b/assets/world_under.mp4 differ
diff --git a/assets/yusen-trailer.mp4 b/assets/yusen-trailer.mp4
new file mode 100644
index 0000000..ab0cd98
Binary files /dev/null and b/assets/yusen-trailer.mp4 differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..6c5b90f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,572 @@
+
+
+
+
+
+宇森 · Yusen|活的文明系统模拟
+
+
+
+
+
+
+
+
+ 宇森YUSEN
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
宇森
+
你不是玩家,你是园丁。
+
一款活的文明系统模拟——播种一个会自己生长的世界,从地心到陨石星空,见证文明在垂直切面中自发演化。
+
+
+
+
+
+
+
+
+
+
+
+
+ 等级制度TIERS & RANK SYSTEM
+
+
+
+
+
+
+
+
+
+
全部
+
综合讨论
+
玩法攻略
+
同人创作
+
BUG 反馈
+
+
+
+
+
+
PIN【公告】宇森官网第一阶段上线,欢迎园丁们入驻128 回复 · 官方
+
新手向:园丁视角的三种开局思路42 回复 · 行者
+
你们更喜欢哪种族?来投个票76 回复 · 雾岛
+
手绘了我的主世界浮空岛,求轻喷31 回复 · 青柠
+
反馈:飞入微观时偶现卡顿9 回复 · K
+
地下矿脉怎么规划最省心?18 回复 · 老周
+
+
+
+
+
+
+ 公告ANNOUNCEMENTS
+
+
2026.07.09
宇森官网第一阶段上线:介绍 / 特色 / 背景 / 规则 / 图鉴 / 论坛 / 公告 七块,单页切换呈现,介绍页即概念宣传片。
+
2026.07.09
图鉴系统升级:种族 204 条、系别/性格/天赋/神器/传奇事件全面扩量,装备槽位对齐 头/手/胸/裤/鞋/戒指(双)/项链/宝物;全部缩略图改为程序化矢量插画,零 AI 生图。
+
2026.07.08
概念宣传片《垂直生长》完成,呈现五层世界自上而下生长的镜头语言(天空层改为云朵地基块,星空层改为陨石科技带)。
+
2026.07.01
园丁视角核心玩法原型启动,首版六边形地图与活 NPC 验证中。
+
2026.06.20
图鉴系统规划确定:种族 / 建筑 / 生物 / 神器 四大类目,美术持续补充中。
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/login.html b/login.html
new file mode 100644
index 0000000..d4b84dc
--- /dev/null
+++ b/login.html
@@ -0,0 +1,193 @@
+
+
+
+
+
+宇森 · 登录
+
+
+
+
+
+
+
宇森
+
YUSEN · GARDEN OF CIVILIZATION
+
你不是玩家,你是园丁。
+
+
+
+
登录后即可进入游戏
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/terrain_preview.html b/terrain_preview.html
new file mode 100644
index 0000000..de72eeb
--- /dev/null
+++ b/terrain_preview.html
@@ -0,0 +1,154 @@
+草地变体预览
+草地变体预览
视频为动态循环播放(与游戏内一致)。扫一眼,哪个不顺眼就告诉我编号,我直接删。
+动态视频变体(游戏中实际使用的 7 个)
+
+#2
+
+
+
+

+
plain_2.png
+
+
+
+
+#4
+
+
+
+

+
plain_4.png
+
+
+
+
+#5
+
+
+
+

+
plain_5.png
+
+
+
+
+#8
+
+
+
+

+
plain_8.png
+
+
+
+
+#12
+
+
+
+

+
plain_12.png
+
+
+
+
+#13
+
+
+
+

+
plain_13.png
+
+
+
+
+#14
+
+
+
+

+
plain_14.png
+
+
静态 PNG 变体(含 #16 兜底,共 8 个)
+
+#2
+
+
+

+
plain_2.png
+
+
+
+
+#4
+
+
+

+
plain_4.png
+
+
+
+
+#5
+
+
+

+
plain_5.png
+
+
+
+
+#8
+
+
+

+
plain_8.png
+
+
+
+
+#12
+
+
+

+
plain_12.png
+
+
+
+
+#13
+
+
+

+
plain_13.png
+
+
+
+
+#14
+
+
+

+
plain_14.png
+
+
+
+
+#16
+
+
+

+
plain_16.png
+
+
\ No newline at end of file
diff --git a/world.html b/world.html
new file mode 100644
index 0000000..95767bb
--- /dev/null
+++ b/world.html
@@ -0,0 +1,3112 @@
+
+
+
+
+
+宇森 - 微观场景
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
宇森大地
+
+
坐标: (0, 0)
+
+
+
+
+
+
+
+
+
+
✦星空
+
☁天空
+
◈大地
+
◎地下
+
◆地心
+
+
+
+
+
+
+
+
+
+
+
+
+
+
💡 拖拽空白处可平移视角,滚轮缩放沙盘
+
+
+
+
+
+
+
+
+
+
+
+
+
微观世界 · 工具栏
+
+
+
+
+
+
+
素材工具栏
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
🔨 建造
+
+
+
+
+
+
+
+
+
+ 高度
+
+ 3 · 森林
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+