Initial commit: RHINE LAB · ANALYSIS OS:三维界面与动效实验(本仓库不含个人归档索引数据)

This commit is contained in:
WpyQwq
2026-09-19 13:04:56 +08:00
commit 3f422218a5
1098 changed files with 39410 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
import { defineConfig } from "vite";
import { existsSync, readFileSync } from "node:fs";
import { createHash } from "node:crypto";
// 本地归档服务:开发与预览都把 /archive-api 代理到 127.0.0.1,并在代理层注入
// 每次启动生成的访问令牌。令牌不进入浏览器,外部网页无法直接调用该服务。
const archiveConfig = JSON.parse(readFileSync("archive.config.json", "utf8"));
const archivePort = Number(archiveConfig.port ?? 43117);
const readArchiveToken = () => {
try {
return readFileSync(".archive-token", "utf8").trim();
} catch {
return "";
}
};
const archiveProxy = {
"/archive-api": {
target: `http://127.0.0.1:${archivePort}`,
changeOrigin: false,
ws: false,
rewrite: (url: string) => url.replace(/^\/archive-api/, ""),
configure: (proxy: {
on: (event: string, handler: (req: { setHeader(name: string, value: string): void }) => void) => void;
}) => {
proxy.on("proxyReq", (proxyReq) => {
const token = readArchiveToken();
if (token) proxyReq.setHeader("x-archive-token", token);
});
},
},
};
// Keep Blender's stable source/export paths, while production URLs identify
// exact bytes and can be cached without revalidation across deployments.
const models = ["archive-cassette", "archive-assembly"].map(name => {
const source = readFileSync(`public/assets/${name}.glb`);
const hash = createHash("sha256").update(source).digest("hex").slice(0,16);
return { key:`assets/${name}.glb`, fileName:`assets/${name}.${hash}.glb`, source };
});
const hasNovecento = ["Normal", "DemiBold", "Bold"].every(weight =>
existsSync(`public/fonts/novecento/webFonts/NovecentoSansWide${weight}/font.woff2`),
);
export default defineConfig(({ mode }) => ({
base: mode === "wallpaper" ? "./" : "/",
server: { proxy: archiveProxy },
preview: { proxy: archiveProxy },
define: {
__RHINE_MODELS__: JSON.stringify(Object.fromEntries(models.map(model => [model.key,model.fileName]))),
__RHINE_NOVECENTO__: JSON.stringify(hasNovecento),
},
plugins: [{
name: "versioned-model-assets", apply: "build",
buildStart() { for (const model of models) this.emitFile({type:"asset",fileName:model.fileName,source:model.source}); },
}, ...(mode === "wallpaper" ? [{
name: "wallpaper-host",
transformIndexHtml(html: string) {
return { html: html.replace(/\s*<link rel="manifest"[^>]*>/, ""), tags: [{
tag: "script", children: readFileSync("wallpaper/host.js", "utf8"), injectTo: "head-prepend" as const,
}] };
},
}] : [])],
}));