Files
boundless/public/painterly/loader.js
T
吴璨 fad9760265 自部署多端同步:服务端、实时协作、口令登录与油画加载动画
- 新增 Node 服务端(Hono + Hocuspocus + node:sqlite),数据保存在服务器
- 基于 Yjs 的多端实时同步,本机 IndexedDB 离线缓存,撤销只针对本机操作
- 空间(标签)有独立地址,增删改通过接口同步到所有设备
- 口令登录(签名 Cookie 会话、登录限流、同源校验)
- 图片上传到服务器,过大照片上传前自动压缩
- 历史版本(自动/手动保存、一键恢复)、跨空间搜索、在线设备
- 随机油画加载动画(Painting Loaders,本地收录 p5 / p5.brush)
- 选中样式与拖拽性能优化:拖动结束后才同步位置
- Docker / docker-compose 部署,README 与 CLAUDE.md 更新
2026-10-21 18:09:03 +08:00

73 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =====================================================================
* loader.js — 无界笺的加载动画外壳。
*
* 绘画引擎与 12 幅画作来自 Painting Loaders
* (https://painterly.design-tools.workers.dev,作者 Sasha / x.com/aleksksaa),
* engine.js 与 style-*.js 原样保留。这里只负责:随机挑一幅(不与上次重复),
* 把画布铺满本页,并通知父页面已经开始作画。
*
* 本页通过 iframe 嵌入,p5 的全局模式不会污染主应用。
* ===================================================================== */
const PAINTINGS = [
{ key: 'garden', style: 'impressionismGarden', name: '花园', label: 'Garden' },
{ key: 'dawn', style: 'impressionismDawn', name: '晨曦', label: 'Dawn' },
{ key: 'willow', style: 'impressionismWillow', name: '垂柳', label: 'Willow' },
{ key: 'wisteria', style: 'impressionismWisteria', name: '紫藤', label: 'Wisteria' },
{ key: 'orchard', style: 'impressionismOrchard', name: '果园', label: 'Orchard' },
{ key: 'irises', style: 'impressionismIrises', name: '鸢尾', label: 'Irises' },
{ key: 'poppies', style: 'impressionismPoppies', name: '虞美人', label: 'Poppies' },
{ key: 'koi', style: 'impressionismKoi', name: '锦鲤', label: 'Koi' },
{ key: 'roses', style: 'impressionismRoses', name: '玫瑰', label: 'Roses' },
{ key: 'oranges', style: 'impressionismOranges', name: '橘子', label: 'Oranges' },
{ key: 'sail', style: 'impressionismSail', name: '远帆', label: 'Sail' },
{ key: 'dusk', style: 'abstractionDusk', name: '黄昏', label: 'Dusk' },
];
const LAST_KEY = 'boundless-last-painting';
function choosePainting() {
const wanted = new URLSearchParams(location.search).get('p');
const exact = PAINTINGS.find((item) => item.key === wanted);
if (exact) return exact;
let last = null;
try { last = localStorage.getItem(LAST_KEY); } catch (e) { /* 隐私模式 */ }
const pool = PAINTINGS.filter((item) => item.key !== last);
const picked = pool[Math.floor(Math.random() * pool.length)] || PAINTINGS[0];
try { localStorage.setItem(LAST_KEY, picked.key); } catch (e) { /* 隐私模式 */ }
return picked;
}
const painting = choosePainting();
const config = window.STYLES[painting.style];
document.documentElement.style.background = config.palette.ground;
function notifyParent(type) {
if (window.parent === window) return;
window.parent.postMessage(
{ source: 'boundless-painterly', type, key: painting.key, name: painting.name, label: painting.label, ground: config.palette.ground },
location.origin,
);
}
notifyParent('chosen');
let engine = null;
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
// p5 全局模式:页面加载后若 window 上有 setup / draw 就会自动开始。
// 系统要求减少动态效果时不作画,只留下画纸底色。
if (!reduceMotion) {
window.setup = function () {
// 画布内部固定 600×600,再由 CSS 缩放;不跟随设备像素比可以省下不少显存
pixelDensity(1);
engine = createEngine(config, { mount: document.body });
engine.setup();
notifyParent('start');
};
window.draw = function () {
if (engine) engine.draw();
};
}