diff --git a/info/.gitignore b/info/.gitignore
new file mode 100644
index 0000000..7585238
--- /dev/null
+++ b/info/.gitignore
@@ -0,0 +1 @@
+book
diff --git a/info/book.toml b/info/book.toml
new file mode 100644
index 0000000..ca64501
--- /dev/null
+++ b/info/book.toml
@@ -0,0 +1,6 @@
+[book]
+authors = ["shenjack"]
+language = "zh"
+multilingual = false
+src = "src"
+title = "namerena"
diff --git a/info/src/SUMMARY.md b/info/src/SUMMARY.md
new file mode 100644
index 0000000..aa74f80
--- /dev/null
+++ b/info/src/SUMMARY.md
@@ -0,0 +1,4 @@
+# 目录
+
+- [介绍](./start.md)
+- [开箱用法](./use.md)
diff --git a/info/src/start.md b/info/src/start.md
new file mode 100644
index 0000000..781a8bd
--- /dev/null
+++ b/info/src/start.md
@@ -0,0 +1,34 @@
+# 介绍
+
+欢迎来到 [fast-namerna](https://fast-namerena.pages.dev/), 一个由 shenjack 和 超导体元素 构建的 namerena 镜像 + 修改版
+
+## 特性
+
+- 基于 [deepmess.com/namerena](https://deepmess.com/namerena/) 的 namerena 版本构建
+- 去除了所有的广告
+- 有多种 (目前其实就两种) 特化分支
+- 完全开源 [GitHub](https://github.com/shenjackyuanjie/fast-namerena)
+
+## 分支
+
+### main
+
+- 最稳定的版本
+- 保证能用
+- 支持 DIY 功能
+- 通过跳过 delay 来加速
+
+### fight
+
+- 通过去掉了 delay 来加速
+- 只支持战斗加速
+ - 当然, 战斗加速也是最快的
+- 不支持 DIY
+- 不支持其他功能 (测号, 开箱)
+
+### latest
+
+- 最新的版本
+- 有可能会出现问题
+- 支持 DIY 功能
+- 通过跳过 delay 来加速
diff --git a/info/src/use.md b/info/src/use.md
new file mode 100644
index 0000000..c665c5c
--- /dev/null
+++ b/info/src/use.md
@@ -0,0 +1,12 @@
+# 开箱用法
+
+## 需求
+
+你需要:
+
+- 你的脑子
+- 你的手
+- 你的电脑
+ - 安装好 nodejs/bun (bun 更好)
+ - 安装好 python (如果你需要写点脚本)
+ - 下载好所需要的
diff --git a/md5-api.ts b/md5-api.ts
new file mode 100644
index 0000000..814b5ff
--- /dev/null
+++ b/md5-api.ts
@@ -0,0 +1,208 @@
+const md5_module = require("./md5.js");
+
+/**
+ * 对战结果的数据结构
+ * 其实只有 source_plr 是有用的, 是赢家之一
+ */
+type FightResult = {
+ message: string;
+ source_plr: string;
+ target_plr: string;
+ affect: string | number;
+};
+
+/**
+ * 每一行具体的胜率结果
+ */
+type WinRate = {
+ round: number;
+ win_count: number;
+};
+
+/**
+ * 胜率的数据结构
+ */
+type WinRateResult = {
+ win_count: number;
+ raw_data: WinRate[];
+};
+
+/**
+ * 用于接收胜率的回调函数
+ * 返回一个 bool, true 表示继续, false 表示停止
+ */
+type WinRateCallback = (run_round: number, win_count: number) => boolean;
+
+/**
+ * 分数的数据结构
+ */
+type Score = {
+ round: number;
+ score: number;
+};
+
+/**
+ * 分数的数据结构
+ */
+type ScoreResult = {
+ score: number;
+ raw_data: Score[];
+};
+
+/**
+ * 用于接收分数的回调函数
+ * 返回一个 bool, true 表示继续, false 表示停止
+ */
+type ScoreCallback = (run_round: number, score: number) => boolean;
+
+/**
+ *
+ * @param names 原始的输入框输入
+ * @returns 对战结果
+ */
+async function fight(names: string): Promise {
+ // 检查一下输入是否合法
+ // 比如里面有没有 !test!
+ if (names.indexOf("!test!") !== -1) {
+ throw new Error("你怎么在对战输入里加 !test!(恼)\n${names}");
+ }
+ return await md5_module.fight(names);
+}
+
+/**
+ * 对于胜率/评分的输入检查
+ * @param names
+ * @returns
+ */
+function test_check(names: string): boolean {
+ const have_test = names.trim().startsWith("!test!");
+
+ return have_test;
+}
+
+/**
+ * 测量胜率
+ * @param names 原始的输入框输入
+ * @param round 战斗的回合数
+ * @returns 胜率结果
+ */
+async function win_rate(names: string, round: number): Promise {
+ // 检查 round 是否合法
+ if (round <= 0) {
+ throw new Error("round 必须大于 0");
+ }
+ if (!test_check(names)) {
+ throw new Error("你怎么在胜率输入里丢了 !test!(恼)\n${names}");
+ }
+ return await md5_module.win_rate(names, round);
+}
+
+/**
+ *
+ * @param names 原始的输入框输入
+ * @param callback 用于接收胜率的回调函数
+ * @returns 胜率结果
+ */
+async function win_rate_callback(
+ names: string,
+ callback: WinRateCallback,
+): Promise {
+ if (!test_check(names)) {
+ throw new Error("你怎么在胜率输入里丢了 !test!(恼)\n${names}");
+ }
+ return await md5_module.win_rate_callback(names, callback);
+}
+
+async function score(names: string, round: number): Promise {
+ // 检查 round 是否合法
+ if (round <= 0) {
+ throw new Error("round 必须大于 0");
+ }
+ if (!test_check(names)) {
+ throw new Error("你怎么在分数输入里丢了 !test!(恼)\n${names}");
+ }
+ return await md5_module.score(names, round);
+}
+
+async function score_callback(
+ names: string,
+ callback: ScoreCallback,
+): Promise {
+ if (!test_check(names)) {
+ throw new Error("你怎么在分数输入里加 !test!(恼)\n${names}");
+ }
+ return await md5_module.score_callback(names, callback);
+}
+
+async function run_any(
+ names: string,
+ round: number,
+): Promise {
+ return await md5_module.run_any(names, round);
+}
+
+const out_limit: number = 1000;
+
+async function wrap_any(names: string, round: number): Promise {
+ const result = await run_any(names, round);
+ if ("message" in result) {
+ // 对战结果
+ return `赢家:|${result.source_plr}|`;
+ }
+ if ("win_count" in result) {
+ // 胜率结果
+ const win_rate = (result.win_count * 100) / round;
+ const win_rate_str = win_rate.toFixed(4);
+ let output_str = `最终胜率:|${win_rate_str}%|(${round}轮)`;
+ // 每 500 轮, 输出一次
+ if (round > out_limit) {
+ // 把所有要找的数据拿出来
+ const output_datas: WinRate[] = [];
+ result.raw_data.forEach((data, index) => {
+ if (data.round % out_limit === 0) {
+ output_datas.push(data);
+ }
+ });
+ output_datas.forEach((data, index) => {
+ const win_rate = (data.win_count * 100) / data.round;
+ output_str += `\n${win_rate.toFixed(2)}%(${data.round})`;
+ });
+ }
+ return output_str;
+ // } else if ('score' in result) {
+ }
+ // 分数结果其实还是个胜率, 不过需要 * 100
+ const win_rate = ((result.score * 10000) / round).toFixed(2);
+ let output_str = `分数:|${win_rate}|(${round}轮)`;
+ if (round > out_limit) {
+ // 把所有要找的数据拿出来
+ const output_datas: Score[] = [];
+ result.raw_data.forEach((data, index) => {
+ if (data.round % out_limit === 0) {
+ output_datas.push(data);
+ }
+ });
+ output_datas.forEach((data, index) => {
+ const win_rate = ((data.score / data.round) * 10000).toFixed(2);
+ output_str += `\n${win_rate}(${data.round})`;
+ });
+ }
+ return output_str;
+}
+
+export {
+ type FightResult,
+ type WinRate,
+ type WinRateResult,
+ type WinRateCallback,
+ type Score,
+ type ScoreResult,
+ type ScoreCallback,
+ fight,
+ win_rate,
+ win_rate_callback,
+ score,
+ score_callback,
+ run_any,
+ wrap_any,
+};