开发指南(iframe 渲染模式)

渲染

参照现有酒馆卡的界面开发方式。 举例说明:

世界书

<Blanc>
时间:11:00
地点:酒店咖啡厅
服饰:白色衬衫领口系着精致的领结,搭配红色西装外套
动作:优雅的端起银质奶壶,缓缓倾倒入散发着香气的红茶里
</Blanc>

正则表达式

<Blanc>\s*时间:(.+?)\n\s*地点:(.+?)\n\s*服饰:(.+?)\n\s*动作:(.+?)\s*</Blanc>

替换为

```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>幕间记录 - Blanc</title> <script src="https://cdn.tailwindcss.com"></script> <style> @import url("https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600&family=Noto+Serif+SC:wght@400;600&display=swap"); body { font-family: "Noto Serif SC", serif; background: linear-gradient(135deg, #2c1810 0%, #4a3228 100%); } .paper { background: linear-gradient(to bottom, #f4e8d0 0%, #e8dcc4 100%); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.3); position: relative; } .paper::before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: repeating-linear-gradient( transparent, transparent 31px, rgba(139, 115, 85, 0.1) 31px, rgba(139, 115, 85, 0.1) 32px ); pointer-events: none; } .wax-seal { width: 80px; height: 80px; background: radial-gradient(circle, #8b0000 0%, #5c0000 100%); border-radius: 50%; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4), inset 0 -2px 4px rgba(0, 0, 0, 0.3); position: relative; animation: sealFloat 3s ease-in-out infinite; } .wax-seal::after { content: "B"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-family: "Cinzel", serif; font-size: 32px; font-weight: 600; color: rgba(244, 232, 208, 0.8); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } @keyframes sealFloat { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-5px); } } .ink-text { color: #2c1810; text-shadow: 0 1px 1px rgba(44, 24, 16, 0.1); } .divider { height: 2px; background: linear-gradient( to right, transparent, #8b7355, transparent ); margin: 20px 0; } .corner-decoration { position: absolute; width: 40px; height: 40px; border: 2px solid rgba(139, 115, 85, 0.3); } .corner-tl { top: 20px; left: 20px; border-right: none; border-bottom: none; } .corner-tr { top: 20px; right: 20px; border-left: none; border-bottom: none; } .corner-bl { bottom: 20px; left: 20px; border-right: none; border-top: none; } .corner-br { bottom: 20px; right: 20px; border-left: none; border-top: none; } .field-label { font-family: "Cinzel", serif; font-size: 12px; letter-spacing: 2px; color: #8b7355; text-transform: uppercase; } .field-value { font-size: 18px; line-height: 1.8; margin-top: 4px; } .fade-in { animation: fadeIn 1s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } </style> </head> <body class="min-h-screen flex items-center justify-center p-4"> <div class="paper max-w-md w-full rounded-sm p-8 fade-in" style="min-height: 600px;" > <div class="corner-decoration corner-tl"></div> <div class="corner-decoration corner-tr"></div> <div class="corner-decoration corner-bl"></div> <div class="corner-decoration corner-br"></div> <div class="flex justify-center mb-6"> <div class="wax-seal"></div> </div> <h1 class="text-center ink-text text-2xl mb-6" style="font-family: 'Cinzel', serif; letter-spacing: 3px;" > 幕间记录 </h1> <div class="divider"></div> <div class="space-y-6 mt-8"> <div class="fade-in" style="animation-delay: 0.2s;"> <div class="field-label">时刻 · Time</div> <div class="field-value ink-text">$1</div> </div> <div class="fade-in" style="animation-delay: 0.4s;"> <div class="field-label">地点 · Location</div> <div class="field-value ink-text">$2</div> </div> <div class="fade-in" style="animation-delay: 0.6s;"> <div class="field-label">服饰 · Attire</div> <div class="field-value ink-text">$3</div> </div> <div class="fade-in" style="animation-delay: 0.8s;"> <div class="field-label">动作 · Action</div> <div class="field-value ink-text">$4</div> </div> </div> <div class="divider mt-8"></div> <div class="text-center mt-6 ink-text opacity-50" style="font-family: 'Cinzel', serif; font-size: 10px; letter-spacing: 2px;" > INTERMISSION · BLANC </div> </div> </body> </html> ``` </details> ### 处理结果 正则替换后的HTML <details> ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>幕间记录 - Blanc</title> <script src="https://cdn.tailwindcss.com"></script> <style> @import url("https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600&family=Noto+Serif+SC:wght@400;600&display=swap"); body { font-family: "Noto Serif SC", serif; background: linear-gradient(135deg, #2c1810 0%, #4a3228 100%); } .paper { background: linear-gradient(to bottom, #f4e8d0 0%, #e8dcc4 100%); box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.3); position: relative; } .paper::before { content: ""; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: repeating-linear-gradient( transparent, transparent 31px, rgba(139, 115, 85, 0.1) 31px, rgba(139, 115, 85, 0.1) 32px ); pointer-events: none; } .wax-seal { width: 80px; height: 80px; background: radial-gradient(circle, #8b0000 0%, #5c0000 100%); border-radius: 50%; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4), inset 0 -2px 4px rgba(0, 0, 0, 0.3); position: relative; animation: sealFloat 3s ease-in-out infinite; } .wax-seal::after { content: "B"; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-family: "Cinzel", serif; font-size: 32px; font-weight: 600; color: rgba(244, 232, 208, 0.8); text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); } @keyframes sealFloat { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-5px); } } .ink-text { color: #2c1810; text-shadow: 0 1px 1px rgba(44, 24, 16, 0.1); } .divider { height: 2px; background: linear-gradient( to right, transparent, #8b7355, transparent ); margin: 20px 0; } .corner-decoration { position: absolute; width: 40px; height: 40px; border: 2px solid rgba(139, 115, 85, 0.3); } .corner-tl { top: 20px; left: 20px; border-right: none; border-bottom: none; } .corner-tr { top: 20px; right: 20px; border-left: none; border-bottom: none; } .corner-bl { bottom: 20px; left: 20px; border-right: none; border-top: none; } .corner-br { bottom: 20px; right: 20px; border-left: none; border-top: none; } .field-label { font-family: "Cinzel", serif; font-size: 12px; letter-spacing: 2px; color: #8b7355; text-transform: uppercase; } .field-value { font-size: 18px; line-height: 1.8; margin-top: 4px; } .fade-in { animation: fadeIn 1s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } </style> </head> <body class="min-h-screen flex items-center justify-center p-4"> <div class="paper max-w-md w-full rounded-sm p-8 fade-in" style="min-height: 600px;" > <div class="corner-decoration corner-tl"></div> <div class="corner-decoration corner-tr"></div> <div class="corner-decoration corner-bl"></div> <div class="corner-decoration corner-br"></div> <div class="flex justify-center mb-6"> <div class="wax-seal"></div> </div> <h1 class="text-center ink-text text-2xl mb-6" style="font-family: 'Cinzel', serif; letter-spacing: 3px;" > 幕间记录 </h1> <div class="divider"></div> <div class="space-y-6 mt-8"> <div class="fade-in" style="animation-delay: 0.2s;"> <div class="field-label">时刻 · Time</div> <div class="field-value ink-text">11:00</div> </div> <div class="fade-in" style="animation-delay: 0.4s;"> <div class="field-label">地点 · Location</div> <div class="field-value ink-text">酒店咖啡厅</div> </div> <div class="fade-in" style="animation-delay: 0.6s;"> <div class="field-label">服饰 · Attire</div> <div class="field-value ink-text"> 白色衬衫领口系着精致的领结,搭配红色西装外套 </div> </div> <div class="fade-in" style="animation-delay: 0.8s;"> <div class="field-label">动作 · Action</div> <div class="field-value ink-text"> 优雅的端起银质奶壶,缓缓倾倒入散发着香气的红茶里 </div> </div> </div> <div class="divider mt-8"></div> <div class="text-center mt-6 ink-text opacity-50" style="font-family: 'Cinzel', serif; font-size: 10px; letter-spacing: 2px;" > INTERMISSION · BLANC </div> </div> </body> </html> ```

最终效果预览

API:调用平台能力

我们将提供一个全局对象 window.$mujian,创作者可以通过这个对象来和平台交互。

发送消息(非同层)

window.$mujian.ai.chat.complete("你要发送的消息内容");

完整代码:

```html <body style="color: white; font-size: 12px"> <button id="send" class="ui-button ui-widget ui-corner-all"> 发送“你好” </button> <script> $("#send").click(async () => { window.$mujian.ai.chat.complete("你好"); // 发送消息 }); </script> </body> ```

dev-chat-sdk1

获取当前作品信息

window.$mujian.ai.chat.project

完整代码:

```html <body style="color: white; font-size: 12px; border:1px solid green"> <div>作品信息:</div> <div id="project">-</div> <div>人设信息:</div> <div id="persona">-</div> <script> $("#project").text(JSON.stringify(window.$mujian.ai.chat.project)); // 获取作品信息 $("#persona").text(JSON.stringify(window.$mujian.ai.chat.settings.persona)); // 获取人设信息 </script> </body> ```

dev-chat-sdk2

获取当前人设信息

window.$mujian.ai.chat.settings.persona

完整代码:

```html <body style="color: white; font-size: 12px; border:1px solid green"> <div>作品信息:</div> <div id="project">-</div> <div>人设信息:</div> <div id="persona">-</div> <script> $("#project").text(JSON.stringify(window.$mujian.ai.chat.project)); // 获取作品信息 $("#persona").text(JSON.stringify(window.$mujian.ai.chat.settings.persona)); // 获取人设信息 </script> </body> ```

dev-chat-sdk2

开场白直接跳转

将你想要跳转到的开场白编号填入下方括号中,编号从1开始,开场白1就是用户进来看到的那一条开场白。 如果填入了不存在的开场白编号,则什么也不会发生。

window.$mujian.ai.chat.setFirstMesIndex(3); // 跳转到开场白3

完整代码:

```html <body style="color: white; font-size: 12px"> <button id="jump" class="ui-button ui-widget ui-corner-all"> 跳转至开场白3 </button> <script> $("#jump").click(async () => { window.$mujian.ai.chat.setFirstMesIndex(3); // 跳转到开场白3 }); </script> </body> ```

点击按钮会直接跳转到开场白3

dev-chat-sdk3

三方库支持

我们在iframe渲染模式下,默认支持以下受信任的三方库:

  • fontawesome-free: 图标库
  • tailwindcss: 样式库
  • jquery: 库
  • jquery-ui: UI库
  • jquery-ui-touch-punch: 触摸事件库

创作者如果想添加更多的库,可以与我们联系,我们将根据实际情况进行评估。

变量方案

筹备中...

限制

为了保障创作者的作品符合安全标准,我们限制了以下行为:

  • 引入三方库

    如果需要引入,请与我们联系。

  • 外部 worker 线程
  • 发起 fetch 网络请求
  • 嵌套外部 iframe

幕间保留根据实际情况随时调整限制的权利。