From df35f18c80360406246bbaa7070d8c4cb580dd21 Mon Sep 17 00:00:00 2001 From: PFiS <69380732+PFiS1737@users.noreply.github.com> Date: Sun, 14 Feb 2021 21:11:27 +0800 Subject: [PATCH] Add files via upload --- autoload.js | 65 ++++++++++ waifu-tips.js | 317 +++++++++++++++++++++++++++++++++++++++++++++ waifu_left.css | 332 ++++++++++++++++++++++++++++++++++++++++++++++++ waifu_right.css | 332 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 1046 insertions(+) create mode 100644 autoload.js create mode 100644 waifu-tips.js create mode 100644 waifu_left.css create mode 100644 waifu_right.css diff --git a/autoload.js b/autoload.js new file mode 100644 index 0000000..83fd938 --- /dev/null +++ b/autoload.js @@ -0,0 +1,65 @@ +// 注意:live2d_path 参数应使用绝对路径 +const live2d_path = "/effect/Live2D/live2d-widget/"; + +// 封装异步加载资源的方法 +function loadExternalResource(url, type) { + return new Promise((resolve, reject) => { + let tag; + + if (type === "css") { + tag = document.createElement("link"); + tag.rel = "stylesheet"; + tag.href = url; + tag.id = "live2d_css"; + } + else if (type === "js") { + tag = document.createElement("script"); + tag.src = url; + } + if (tag) { + tag.onload = () => resolve(url); + tag.onerror = () => reject(url); + document.head.appendChild(tag); + } + }); +} + +// 加载 waifu.css live2d.min.js waifu-tips.js +if (screen.width >= 768) { + // "768"为最低显示宽度,单位为像素 + Promise.all([ + loadExternalResource(live2d_path + "waifu_left.css", "css"), + loadExternalResource(live2d_path + "live2d.min.js", "js"), + loadExternalResource(live2d_path + "waifu-tips.js", "js") + ]).then(() => { + initWidget({ + waifuPath: live2d_path + "waifu-tips.json", + // apiPath: "https://api.zsq.im/live2d/", + apiPath: "https://live2d.fghrsh.net/api/", + // cdnPath: "https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/" + }); + }); +} +// initWidget 第一个参数为 waifu-tips.json 的路径,第二个参数为 API 地址 +// API 后端可自行搭建,参考 https://github.com/fghrsh/live2d_api +// 初始化看板娘会自动加载指定目录下的 waifu-tips.json + +console.log(` + く__,.ヘヽ. / ,ー、 〉 + \ ', !-─‐-i / /´ + /`ー' L//`ヽ、 + / /, /| , , ', + イ / /-‐/ i L_ ハ ヽ! i + レ ヘ 7イ`ト レ'ァ-ト、!ハ| | + !,/7 '0' ´0iソ| | + |.从" _ ,,,, / |./ | + レ'| i>.、,,__ _,.イ / .i | + レ'| | / k_7_/レ'ヽ, ハ. | + | |/i 〈|/ i ,.ヘ | i | + .|/ / i: ヘ! \ | + kヽ>、ハ _,.ヘ、 /、! + !'〈//`T´', \ `'7'ーr' + レ'ヽL__|___i,___,ンレ|ノ + ト-,/ |___./ + 'ー' !_,.: +`); diff --git a/waifu-tips.js b/waifu-tips.js new file mode 100644 index 0000000..6ebb312 --- /dev/null +++ b/waifu-tips.js @@ -0,0 +1,317 @@ +/* + * Live2D Widget + * Original from https://github.com/stevenjoezhang/live2d-widget + * https://github.com/PFiS1737/PFiS_Public_Repository/tree/main/live2d + */ + +const live2d_path = "/effect/Live2D/live2d-widget/"; + +function loadWidget(config) { + let { waifuPath, apiPath, cdnPath } = config; + let useCDN = false, modelList; + if (typeof cdnPath === "string") { + useCDN = true; + if (!cdnPath.endsWith("/")) cdnPath += "/"; + } else if (typeof apiPath === "string") { + if (!apiPath.endsWith("/")) apiPath += "/"; + } else { + console.error("Invalid initWidget argument!"); + return; + } + localStorage.removeItem("waifu-display"); + sessionStorage.removeItem("waifu-text"); + document.body.insertAdjacentHTML("beforeend", `
+
+ +
+ + + + + + + + + +
+
`); + // https://stackoverflow.com/questions/24148403/trigger-css-transition-on-appended-element + setTimeout(() => { + document.getElementById("waifu").style.bottom = 0; + }, 0); + + function randomSelection(obj) { + return Array.isArray(obj) ? obj[Math.floor(Math.random() * obj.length)] : obj; + } + // 检测用户活动状态,并在空闲时显示消息 + let userAction = false, + userActionTimer, + messageTimer, + messageArray = ["好久不见,日子过得好快呢……", "大坏蛋!你都多久没理人家了呀,嘤嘤嘤~", "嗨~快来逗我玩吧!", "拿小拳拳锤你胸口!", "记得把小家加入 Adblock 白名单哦!"]; + window.addEventListener("mousemove", () => userAction = true); + window.addEventListener("keydown", () => userAction = true); + setInterval(() => { + if (userAction) { + userAction = false; + clearInterval(userActionTimer); + userActionTimer = null; + } else if (!userActionTimer) { + userActionTimer = setInterval(() => { + showMessage(randomSelection(messageArray), 6000, 9); + }, 20000); + } + }, 1000); + + (function () { // 根据位置加载 + if (localStorage.getItem("Live2DPlace") === "left") { + document.getElementById("live2d-go-left").style.display = "none"; + } else if (localStorage.getItem("Live2DPlace") === "right") { + document.getElementById("live2d-go-right").style.display = "none"; + document.getElementById("live2d_css").href = live2d_path + "waifu_right.css"; + } + })(); + + (function registerEventListener() { // 工具栏菜单效果 + document.querySelector("#waifu-tool .fa-comment").addEventListener("click", showHitokoto); // 一言API对话 + document.querySelector("#waifu-tool .fa-paper-plane").addEventListener("click", () => { // 飞机大战(雾) + if (window.Asteroids) { + if (!window.ASTEROIDSPLAYERS) window.ASTEROIDSPLAYERS = []; + window.ASTEROIDSPLAYERS.push(new Asteroids()); + } else { + const script = document.createElement("script"); + script.src = "https://cdn.jsdelivr.net/gh/stevenjoezhang/asteroids/asteroids.js"; + document.head.appendChild(script); + } + }); + document.querySelector("#waifu-tool .fa-user-circle").addEventListener("click", loadOtherModel); // 切换模型 + document.querySelector("#waifu-tool .fa-street-view").addEventListener("click", loadRandModel); // 切换材质 + document.querySelector("#waifu-tool .fa-camera-retro").addEventListener("click", () => { // 输出照片 + showMessage("照好了嘛,是不是很可爱呢?", 6000, 9); + Live2D.captureName = "photo.png"; // 输出照片的名字 + Live2D.captureFrame = true; + }); + document.querySelector("#waifu-tool .fa-info-circle").addEventListener("click", () => { // 关于页转跳 + open("https://github.com/PFiS1737/PFiS_Public_Repository/tree/main/page/effect/Live2D/live2d-widget"); //关于页链接 + }); + document.querySelector("#waifu-tool .fa-times").addEventListener("click", () => { // 关闭看板娘 + localStorage.setItem("waifu-display", Date.now()); + showMessage("愿你有一天能与重要的人重逢。", 2000, 11); + document.getElementById("waifu").style.bottom = "-500px"; + setTimeout(() => { + document.getElementById("waifu").style.display = "none"; + document.getElementById("waifu-toggle").classList.add("waifu-toggle-active"); + }, 3000); + }); + document.querySelector("#waifu-tool .fa-chevron-right").addEventListener("click", () => { // 切换看板娘位置(左 => 右) + localStorage.setItem("Live2DPlace", "right"); + showMessage("耶,可以去右边了呢~。", 2000, 11); + document.getElementById("waifu").style.bottom = "-500px"; + setTimeout('document.getElementById("live2d_css").setAttribute("href",live2d_path + "waifu_right.css")',3000); + setTimeout('document.getElementById("waifu").style.bottom = "0px"',3000); + }); + document.querySelector("#waifu-tool .fa-chevron-left").addEventListener("click", () => { // 切换看板娘位置(左 <= 右) + localStorage.setItem("Live2DPlace", "left"); + showMessage("耶,可以去左边了呢~。", 2000, 11); + document.getElementById("waifu").style.bottom = "-500px"; + setTimeout('document.getElementById("live2d_css").setAttribute("href",live2d_path + "waifu_left.css")',3000); + setTimeout('document.getElementById("waifu").style.bottom = "0px"',3000); + }); + const devtools = () => { }; + console.log("%c", devtools); + devtools.toString = () => { + showMessage("哈哈,你打开了控制台,是想要看看我的小秘密吗?", 6000, 9); + }; + window.addEventListener("copy", () => { + showMessage("你都复制了些什么呀,转载要记得加上出处哦!", 6000, 9); + }); + window.addEventListener("visibilitychange", () => { + if (!document.hidden) showMessage("哇,你终于回来了~", 6000, 9); + }); + })(); + + (function welcomeMessage() { + let text; + if (location.pathname === "/") { // 如果是主页 + const now = new Date().getHours(); + if (now > 5 && now <= 7) text = "早上好!一日之计在于晨,美好的一天就要开始了。"; + else if (now > 7 && now <= 11) text = "上午好!工作顺利嘛,不要久坐,多起来走动走动哦!"; + else if (now > 11 && now <= 13) text = "中午了,工作了一个上午,现在是午餐时间!"; + else if (now > 13 && now <= 17) text = "午后很容易犯困呢,今天的运动目标完成了吗?"; + else if (now > 17 && now <= 19) text = "傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~"; + else if (now > 19 && now <= 21) text = "晚上好,今天过得怎么样?"; + else if (now > 21 && now <= 23) text = ["已经这么晚了呀,早点休息吧,晚安~", "深夜时要爱护眼睛呀!"]; + else text = "你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?"; + } else if (document.referrer !== "") { + const referrer = new URL(document.referrer), + domain = referrer.hostname.split(".")[1]; + if (location.hostname === referrer.hostname) text = `欢迎阅读「${document.title.split(" - ")[0]}」`; + else if (domain === "baidu") text = `Hello!来自 百度搜索 的朋友
你是搜索 ${referrer.search.split("&wd=")[1].split("&")[0]} 找到的我吗?`; + else if (domain === "so") text = `Hello!来自 360搜索 的朋友
你是搜索 ${referrer.search.split("&q=")[1].split("&")[0]} 找到的我吗?`; + else if (domain === "google") text = `Hello!来自 谷歌搜索 的朋友
欢迎阅读「${document.title.split(" - ")[0]}」`; + else text = `Hello!来自 ${referrer.hostname} 的朋友`; + } else { + text = `欢迎阅读「${document.title.split(" - ")[0]}」`; + } + showMessage(text, 7000, 8); + })(); + + function showHitokoto() { // 增加 hitokoto.cn 的 API + fetch("https://v1.hitokoto.cn") + .then(response => response.json()) + .then(result => { + const text = `这句一言来自 「${result.from}」,是 ${result.creator} 在 hitokoto.cn 投稿的。`; + showMessage(result.hitokoto, 6000, 9); + setTimeout(() => { + showMessage(text, 4000, 9); + }, 6000); + }); + } + + function showMessage(text, timeout, priority) { + if (!text || (sessionStorage.getItem("waifu-text") && sessionStorage.getItem("waifu-text") > priority)) return; + if (messageTimer) { + clearTimeout(messageTimer); + messageTimer = null; + } + text = randomSelection(text); + sessionStorage.setItem("waifu-text", priority); + const tips = document.getElementById("waifu-tips"); + tips.innerHTML = text; + tips.classList.add("waifu-tips-active"); + messageTimer = setTimeout(() => { + sessionStorage.removeItem("waifu-text"); + tips.classList.remove("waifu-tips-active"); + }, timeout); + } + + (function initModel() { + let modelId = localStorage.getItem("modelId"), + modelTexturesId = localStorage.getItem("modelTexturesId"); + if (modelId === null) { + // 首次访问时加载 指定模型 的 指定材质 + modelId = 2; // 模型 ID + modelTexturesId = 39; // 材质 ID + } + loadModel(modelId, modelTexturesId); + fetch(waifuPath) + .then(response => response.json()) + .then(result => { + window.addEventListener("mouseover", event => { + for (let tips of result.mouseover) { + if (!event.target.matches(tips.selector)) continue; + let text = randomSelection(tips.text); + text = text.replace("{text}", event.target.innerText); + showMessage(text, 4000, 8); + return; + } + }); + window.addEventListener("click", event => { + for (let tips of result.click) { + if (!event.target.matches(tips.selector)) continue; + let text = randomSelection(tips.text); + text = text.replace("{text}", event.target.innerText); + showMessage(text, 4000, 8); + return; + } + }); + result.seasons.forEach(tips => { + const now = new Date(), + after = tips.date.split("-")[0], + before = tips.date.split("-")[1] || after; + if ((after.split("/")[0] <= now.getMonth() + 1 && now.getMonth() + 1 <= before.split("/")[0]) && (after.split("/")[1] <= now.getDate() && now.getDate() <= before.split("/")[1])) { + let text = randomSelection(tips.text); + text = text.replace("{year}", now.getFullYear()); + //showMessage(text, 7000, true); + messageArray.push(text); + } + }); + }); + })(); + + async function loadModelList() { + const response = await fetch(`${cdnPath}model_list.json`); + modelList = await response.json(); + } + + async function loadModel(modelId, modelTexturesId, message) { + localStorage.setItem("modelId", modelId); + localStorage.setItem("modelTexturesId", modelTexturesId); + showMessage(message, 4000, 10); + if (useCDN) { + if (!modelList) await loadModelList(); + const target = randomSelection(modelList.models[modelId]); + loadlive2d("live2d", `${cdnPath}model/${target}/index.json`); + } else { + loadlive2d("live2d", `${apiPath}get/?id=${modelId}-${modelTexturesId}`); + console.log(`Live2D 模型 ${modelId}-${modelTexturesId} 加载完成`); + } + } + + async function loadRandModel() { + const modelId = localStorage.getItem("modelId"), + modelTexturesId = localStorage.getItem("modelTexturesId"); + if (useCDN) { + if (!modelList) await loadModelList(); + const target = randomSelection(modelList.models[modelId]); + loadlive2d("live2d", `${cdnPath}model/${target}/index.json`); + showMessage("我的新衣服好看嘛?", 4000, 10); + } else { + // 材质加载方式, 可选 "rand"(随机), "switch"(顺序) + fetch(`${apiPath}switch_textures/?id=${modelId}-${modelTexturesId}`) + .then(response => response.json()) + .then(result => { + if (result.textures.id === 1 && (modelTexturesId === 1 || modelTexturesId === 0)) showMessage("我还没有其他衣服呢!", 4000, 10); + else loadModel(modelId, result.textures.id, "我的新衣服好看嘛?"); + }); + } + } + + async function loadOtherModel() { + let modelId = localStorage.getItem("modelId"); + if (useCDN) { + if (!modelList) await loadModelList(); + const index = (++modelId >= modelList.models.length) ? 0 : modelId; + loadModel(index, 0, modelList.messages[index]); + } else { + fetch(`${apiPath}switch/?id=${modelId}`) + .then(response => response.json()) + .then(result => { + loadModel(result.model.id, 0, result.model.message); + }); + } + } +} + +function initWidget(config, apiPath) { + if (typeof config === "string") { + config = { + waifuPath: config, + apiPath + }; + } + document.body.insertAdjacentHTML("beforeend", `
+ 看板娘 +
`); + const toggle = document.getElementById("waifu-toggle"); + toggle.addEventListener("click", () => { + toggle.classList.remove("waifu-toggle-active"); + if (toggle.getAttribute("first-time")) { + loadWidget(config); + toggle.removeAttribute("first-time"); + } else { + localStorage.removeItem("waifu-display"); + document.getElementById("waifu").style.display = ""; + setTimeout(() => { + document.getElementById("waifu").style.bottom = 0; + }, 0); + } + }); + if (localStorage.getItem("waifu-display") && Date.now() - localStorage.getItem("waifu-display") <= 86400000) { + toggle.setAttribute("first-time", true); + setTimeout(() => { + toggle.classList.add("waifu-toggle-active"); + }, 0); + } else { + loadWidget(config); + } +} diff --git a/waifu_left.css b/waifu_left.css new file mode 100644 index 0000000..04b52ec --- /dev/null +++ b/waifu_left.css @@ -0,0 +1,332 @@ +/* 看板娘隐藏后的“看板娘”按钮 */ +#waifu-toggle { + background-color: #fa0; + border-radius: 5px; + bottom: 66px; + color: #fff; + cursor: pointer; + font-size: 12px; + left: 0; + margin-left: -100px; + padding: 5px 2px 5px 5px; + position: fixed; + transition: margin-left 1s; + width: 60px; + writing-mode: vertical-rl; + z-index: 1000; +} + +#waifu-toggle.waifu-toggle-active { + margin-left: -50px; +} + +#waifu-toggle.waifu-toggle-active:hover { + margin-left: -30px; +} + +/* 看板娘主体 */ +#waifu { + bottom: -1000px; + left: 0; + line-height: 0; + position: fixed; + transform: translateY(3px); + /* margin-bottom: -10px; */ + transition: transform .3s ease-in-out, bottom 3s ease-in-out; + z-index: 1000; +} + +#waifu:hover { + transform: translateY(0); +} + +/* 看板娘对话框 */ +#waifu-tips { + animation: shake 50s ease-in-out 5s infinite; + background-color: rgba(236, 217, 188, .5); + border: 1px solid rgba(224, 186, 140, .62); + border-radius: 12px; + box-shadow: 0 3px 15px 2px rgba(191, 158, 118, .2); + font-size: 14px; + line-height: 24px; + margin: -30px 20px; + min-height: 70px; + opacity: 0; + overflow: hidden; + padding: 5px 10px; + position: absolute; + text-overflow: ellipsis; + transition: opacity 1s; + width: 250px; + word-break: break-all; + /* display: none !important; */ +} + +#waifu-tips.waifu-tips-active { + opacity: 1; + transition: opacity .2s; +} + +#waifu-tips span { + color: #0099cc; +} + +#waifu #live2d { + cursor: grab; + height: 300px; + position: relative; + width: 300px; +} + +#waifu #live2d:active { + cursor: grabbing; +} + +/* 工具栏 */ +#waifu-tool { + color: #aaa; + opacity: 0; + position: absolute; + right: -10px; + top: 55px; + transition: opacity 1s; +} + +#waifu:hover #waifu-tool { + opacity: 1; +} + +#waifu-tool span { + color: #5b6c7d; + cursor: pointer; + display: block; + line-height: 30px; + text-align: center; + transition: color .3s; +} + +#waifu-tool .fa-chevron-right { + color: #5b6c7d; + cursor: pointer; + display: block; + margin: 7px 0px; + text-align: center; + transition: color .3s; +} + +#waifu-tool .fa-chevron-left { + color: #5b6c7d; + cursor: pointer; + display: block; + margin-top: 23px; + text-align: center; + transition: color .3s; +} + +/* 工具栏触碰后的颜色 */ +#waifu-tool span:hover { + color: #0684bd; + /* color: #34495e; */ +} + +@keyframes shake { + 2% { + transform: translate(.5px, -1.5px) rotate(-.5deg); + } + + 4% { + transform: translate(.5px, 1.5px) rotate(1.5deg); + } + + 6% { + transform: translate(1.5px, 1.5px) rotate(1.5deg); + } + + 8% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 10% { + transform: translate(.5px, 2.5px) rotate(.5deg); + } + + 12% { + transform: translate(1.5px, 1.5px) rotate(.5deg); + } + + 14% { + transform: translate(.5px, .5px) rotate(.5deg); + } + + 16% { + transform: translate(-1.5px, -.5px) rotate(1.5deg); + } + + 18% { + transform: translate(.5px, .5px) rotate(1.5deg); + } + + 20% { + transform: translate(2.5px, 2.5px) rotate(1.5deg); + } + + 22% { + transform: translate(.5px, -1.5px) rotate(1.5deg); + } + + 24% { + transform: translate(-1.5px, 1.5px) rotate(-.5deg); + } + + 26% { + transform: translate(1.5px, .5px) rotate(1.5deg); + } + + 28% { + transform: translate(-.5px, -.5px) rotate(-.5deg); + } + + 30% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 32% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 34% { + transform: translate(2.5px, 2.5px) rotate(-.5deg); + } + + 36% { + transform: translate(.5px, -1.5px) rotate(.5deg); + } + + 38% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 40% { + transform: translate(-.5px, 2.5px) rotate(.5deg); + } + + 42% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 44% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 46% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 48% { + transform: translate(2.5px, -.5px) rotate(.5deg); + } + + 50% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 52% { + transform: translate(-.5px, 1.5px) rotate(.5deg); + } + + 54% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 56% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 58% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 60% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 62% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 64% { + transform: translate(-1.5px, 1.5px) rotate(1.5deg); + } + + 66% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 68% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 70% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 72% { + transform: translate(-.5px, -1.5px) rotate(1.5deg); + } + + 74% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 76% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 78% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 80% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 82% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 84% { + transform: translate(-.5px, .5px) rotate(1.5deg); + } + + 86% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 88% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 90% { + transform: translate(-1.5px, -.5px) rotate(-.5deg); + } + + 92% { + transform: translate(-1.5px, -1.5px) rotate(1.5deg); + } + + 94% { + transform: translate(.5px, .5px) rotate(-.5deg); + } + + 96% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 98% { + transform: translate(-1.5px, -1.5px) rotate(-.5deg); + } + + 0%, 100% { + transform: translate(0, 0) rotate(0); + } +} diff --git a/waifu_right.css b/waifu_right.css new file mode 100644 index 0000000..3598560 --- /dev/null +++ b/waifu_right.css @@ -0,0 +1,332 @@ +/* 看板娘隐藏后的“看板娘”按钮 */ +#waifu-toggle { + background-color: #fa0; + border-radius: 5px; + bottom: 66px; + color: #fff; + cursor: pointer; + font-size: 12px; + right: 0; + margin-right: -100px; + padding: 5px 2px 5px 5px; + position: fixed; + transition: margin-right 1s; + width: 60px; + writing-mode: vertical-lr; + z-index: 1000; +} + +#waifu-toggle.waifu-toggle-active { + margin-right: -40px; +} + +#waifu-toggle.waifu-toggle-active:hover { + margin-right: -20px; +} + +/* 看板娘主体 */ +#waifu { + bottom: -1000px; + right: 0; + line-height: 0; + position: fixed; + transform: translateY(3px); + /* margin-bottom: -10px; */ + transition: transform .3s ease-in-out, bottom 3s ease-in-out; + z-index: 1000; +} + +#waifu:hover { + transform: translateY(0); +} + +/* 看板娘对话框 */ +#waifu-tips { + animation: shake 50s ease-in-out 5s infinite; + background-color: rgba(236, 217, 188, .5); + border: 1px solid rgba(224, 186, 140, .62); + border-radius: 12px; + box-shadow: 0 3px 15px 2px rgba(191, 158, 118, .2); + font-size: 14px; + line-height: 24px; + margin: -30px 20px; + min-height: 70px; + opacity: 0; + overflow: hidden; + padding: 5px 10px; + position: absolute; + text-overflow: ellipsis; + transition: opacity 1s; + width: 250px; + word-break: break-all; + /* display: none !important; */ +} + +#waifu-tips.waifu-tips-active { + opacity: 1; + transition: opacity .2s; +} + +#waifu-tips span { + color: #0099cc; +} + +#waifu #live2d { + cursor: grab; + height: 300px; + position: relative; + width: 300px; +} + +#waifu #live2d:active { + cursor: grabbing; +} + +/* 工具栏 */ +#waifu-tool { + color: #aaa; + opacity: 0; + position: absolute; + left: 10px; + top: 55px; + transition: opacity 1s; +} + +#waifu:hover #waifu-tool { + opacity: 1; +} + +#waifu-tool span { + color: #5b6c7d; + cursor: pointer; + display: block; + line-height: 30px; + text-align: center; + transition: color .3s; +} + +#waifu-tool .fa-chevron-right { + color: #5b6c7d; + cursor: pointer; + display: block; + margin: 7px 0px; + text-align: center; + transition: color .3s; +} + +#waifu-tool .fa-chevron-left { + color: #5b6c7d; + cursor: pointer; + display: block; + margin-top: 23px; + text-align: center; + transition: color .3s; +} + +/* 工具栏触碰后的颜色 */ +#waifu-tool span:hover { + color: #0684bd; + /* color: #34495e; */ +} + +@keyframes shake { + 2% { + transform: translate(.5px, -1.5px) rotate(-.5deg); + } + + 4% { + transform: translate(.5px, 1.5px) rotate(1.5deg); + } + + 6% { + transform: translate(1.5px, 1.5px) rotate(1.5deg); + } + + 8% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 10% { + transform: translate(.5px, 2.5px) rotate(.5deg); + } + + 12% { + transform: translate(1.5px, 1.5px) rotate(.5deg); + } + + 14% { + transform: translate(.5px, .5px) rotate(.5deg); + } + + 16% { + transform: translate(-1.5px, -.5px) rotate(1.5deg); + } + + 18% { + transform: translate(.5px, .5px) rotate(1.5deg); + } + + 20% { + transform: translate(2.5px, 2.5px) rotate(1.5deg); + } + + 22% { + transform: translate(.5px, -1.5px) rotate(1.5deg); + } + + 24% { + transform: translate(-1.5px, 1.5px) rotate(-.5deg); + } + + 26% { + transform: translate(1.5px, .5px) rotate(1.5deg); + } + + 28% { + transform: translate(-.5px, -.5px) rotate(-.5deg); + } + + 30% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 32% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 34% { + transform: translate(2.5px, 2.5px) rotate(-.5deg); + } + + 36% { + transform: translate(.5px, -1.5px) rotate(.5deg); + } + + 38% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 40% { + transform: translate(-.5px, 2.5px) rotate(.5deg); + } + + 42% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 44% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 46% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 48% { + transform: translate(2.5px, -.5px) rotate(.5deg); + } + + 50% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 52% { + transform: translate(-.5px, 1.5px) rotate(.5deg); + } + + 54% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 56% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 58% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 60% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 62% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 64% { + transform: translate(-1.5px, 1.5px) rotate(1.5deg); + } + + 66% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 68% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 70% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 72% { + transform: translate(-.5px, -1.5px) rotate(1.5deg); + } + + 74% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 76% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 78% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 80% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 82% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 84% { + transform: translate(-.5px, .5px) rotate(1.5deg); + } + + 86% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 88% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 90% { + transform: translate(-1.5px, -.5px) rotate(-.5deg); + } + + 92% { + transform: translate(-1.5px, -1.5px) rotate(1.5deg); + } + + 94% { + transform: translate(.5px, .5px) rotate(-.5deg); + } + + 96% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 98% { + transform: translate(-1.5px, -1.5px) rotate(-.5deg); + } + + 0%, 100% { + transform: translate(0, 0) rotate(0); + } +}