F_win.html 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Interactive Pet Widget</title>
  6. <style>
  7. /* Main container styles */
  8. #vpet-container {
  9. position: fixed;
  10. bottom: 20px;
  11. left: 50%;
  12. transform: translateX(-50%);
  13. cursor: pointer;
  14. z-index: 9999;
  15. display: flex;
  16. flex-direction: column;
  17. align-items: center;
  18. user-select: none;
  19. }
  20. /* Pet image container */
  21. #vpet {
  22. width: 180px;
  23. height: 180px;
  24. overflow: hidden;
  25. image-rendering: pixelated;
  26. position: relative;
  27. }
  28. #vpet img {
  29. width: 100%;
  30. height: 100%;
  31. object-fit: contain;
  32. pointer-events: none;
  33. }
  34. /* Corner trigger button */
  35. #corner-trigger {
  36. position: absolute;
  37. top: 5px;
  38. right: 5px;
  39. width: 20px;
  40. height: 20px;
  41. background-image: url('images/边角/vpeticon.png');
  42. background-size: contain;
  43. background-repeat: no-repeat;
  44. cursor: pointer;
  45. z-index: 10000;
  46. opacity: 0.7;
  47. transition: opacity 0.2s;
  48. }
  49. #corner-trigger:hover {
  50. opacity: 1;
  51. }
  52. /* System button */
  53. #system-btn {
  54. position: absolute;
  55. top: 5px;
  56. left: 5px;
  57. width: 20px;
  58. height: 20px;
  59. background-color: rgba(255,255,255,0.2);
  60. border-radius: 50%;
  61. display: flex;
  62. align-items: center;
  63. justify-content: center;
  64. color: white;
  65. font-size: 12px;
  66. cursor: pointer;
  67. z-index: 10000;
  68. transition: all 0.2s;
  69. border: none;
  70. }
  71. #system-btn:hover {
  72. background-color: rgba(255,255,255,0.3);
  73. transform: scale(1.1);
  74. }
  75. /* Settings panel */
  76. #settings-panel {
  77. display: none;
  78. background: rgba(50, 50, 50, 0.9);
  79. border-radius: 4px;
  80. padding: 1px 4px;
  81. margin-top: 4px;
  82. backdrop-filter: blur(4px);
  83. box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
  84. z-index: 10001;
  85. flex-direction: row;
  86. align-items: center;
  87. width: 33.33vw;
  88. max-width: 200px;
  89. height: calc((100vh / 16) / 3);
  90. min-height: 10px;
  91. justify-content: space-around;
  92. box-sizing: border-box;
  93. }
  94. /* Button styles */
  95. .settings-btn {
  96. display: inline-flex;
  97. padding: 0 4px;
  98. background: none;
  99. border: none;
  100. color: #fff;
  101. cursor: pointer;
  102. transition: all 0.1s;
  103. position: relative;
  104. overflow: hidden;
  105. margin: 0 1px;
  106. text-align: center;
  107. border-radius: 2px;
  108. white-space: nowrap;
  109. font-size: 0.6em;
  110. min-width: 30px;
  111. height: calc((100% - 2px) * 5 / 4);
  112. align-items: center;
  113. justify-content: center;
  114. border-bottom: calc(((100% - 2px) * 5 / 4) / 5) solid transparent;
  115. }
  116. .settings-btn:hover:not(.task-btn) {
  117. background: rgba(255, 255, 255, 0.05);
  118. border-bottom-color: rgba(255, 255, 255, 0.2);
  119. }
  120. /* Ripple effect */
  121. .ripple {
  122. position: absolute;
  123. border-radius: 50%;
  124. background: rgba(255, 255, 255, 0.2);
  125. transform: scale(0);
  126. animation: ripple 0.4s linear;
  127. pointer-events: none;
  128. }
  129. @keyframes ripple {
  130. to {
  131. transform: scale(2);
  132. opacity: 0;
  133. }
  134. }
  135. /* Task button styles */
  136. .task-btn {
  137. background: linear-gradient(45deg, #2ed573, #1e90ff);
  138. padding: 0 3px;
  139. font-size: 0.55em;
  140. border-bottom: calc(((100% - 2px) * 5 / 4) / 5) solid rgba(0, 0, 0, 0.15);
  141. display: flex;
  142. align-items: center;
  143. height: calc((100% - 2px) * 5 / 4);
  144. }
  145. .task-btn:hover {
  146. transform: scale(1.01) !important;
  147. border-bottom-color: rgba(255, 255, 255, 0.3);
  148. }
  149. /* Task counter */
  150. .task-counter {
  151. font-size: 0.4em;
  152. background: rgba(0,0,0,0.3);
  153. padding: 0 2px;
  154. border-radius: 4px;
  155. margin-left: 2px;
  156. line-height: normal;
  157. display: inline-flex;
  158. align-items: center;
  159. height: 66.67%;
  160. transform: translateY(2px);
  161. }
  162. .task-badge {
  163. position: absolute;
  164. top: -2px;
  165. right: -2px;
  166. width: 6px;
  167. height: 6px;
  168. background: #ff4757;
  169. border-radius: 50%;
  170. animation: taskPulse 1.5s infinite;
  171. display: none;
  172. border: 1px solid rgba(50, 50, 50, 0.9);
  173. }
  174. @keyframes taskPulse {
  175. 0% { transform: scale(1); }
  176. 50% { transform: scale(1.1); }
  177. 100% { transform: scale(1); }
  178. }
  179. </style>
  180. </head>
  181. <body>
  182. <div id="vpet-container">
  183. <div id="vpet">
  184. <img id="pet-sprite" src="images/待机/待机_001.png">
  185. <div id="corner-trigger"></div>
  186. <div id="system-btn">⚙</div>
  187. </div>
  188. <div id="settings-panel">
  189. <div class="task-badge"></div>
  190. <button class="settings-btn" id="scale-btn">🔄尺寸</button>
  191. <button id="assistant-btn" class="settings-btn">💡助手</button>
  192. <button class="settings-btn task-btn" id="task-btn">📝任务</button>
  193. <button class="settings-btn" id="settings-btn">⚙设置</button>
  194. </div>
  195. </div>
  196. <script>
  197. // Animation configuration
  198. const frames = Array.from({length: 13}, (_, i) =>
  199. `images/待机/待机_${String(i+1).padStart(3, '0')}.png`);
  200. const dragFrames = Array.from({length: 22}, (_, i) =>
  201. `images/提起/提起_${String(i+1).padStart(3, '0')}.png`);
  202. // System state
  203. let currentFrame = 0;
  204. let currentScale = 1.0;
  205. let isDragging = false;
  206. let dragFrameIndex = 0;
  207. const petImage = document.getElementById('pet-sprite');
  208. const container = document.getElementById('vpet-container');
  209. const cornerTrigger = document.getElementById('corner-trigger');
  210. // Store original position
  211. let originalPosition = {
  212. bottom: '20px',
  213. left: '50%',
  214. transform: 'translateX(-50%)'
  215. };
  216. // Auto-play animation
  217. let idleAnimation;
  218. function startIdleAnimation() {
  219. idleAnimation = setInterval(() => {
  220. if (!isDragging) {
  221. petImage.src = frames[currentFrame];
  222. currentFrame = (currentFrame + 1) % frames.length;
  223. }
  224. }, 100);
  225. }
  226. startIdleAnimation();
  227. // Ripple effect function
  228. function createRipple(event) {
  229. const button = event.currentTarget;
  230. const circle = document.createElement("span");
  231. const diameter = Math.max(button.clientWidth, button.clientHeight);
  232. const radius = diameter / 2;
  233. circle.style.width = circle.style.height = `${diameter}px`;
  234. circle.style.left = `${event.clientX - button.getBoundingClientRect().left - radius}px`;
  235. circle.style.top = `${event.clientY - button.getBoundingClientRect().top - radius}px`;
  236. circle.classList.add("ripple");
  237. const ripple = button.getElementsByClassName("ripple")[0];
  238. if (ripple) {
  239. ripple.remove();
  240. }
  241. button.appendChild(circle);
  242. }
  243. // Size toggle
  244. function toggleScale() {
  245. currentScale = currentScale === 1.0 ? 0.8 : 1.0;
  246. container.style.transform = `translateX(-50%) scale(${currentScale})`;
  247. originalPosition.transform = `translateX(-50%) scale(${currentScale})`;
  248. }
  249. // Assistant button feedback
  250. function assistantHint() {
  251. const btn = document.getElementById('assistant-btn');
  252. btn.style.color = '#ffdd00';
  253. setTimeout(() => {
  254. btn.style.color = '#fff';
  255. }, 200);
  256. }
  257. // System button function
  258. function systemHint() {
  259. const btn = document.getElementById('system-btn');
  260. btn.style.backgroundColor = 'rgba(100, 200, 255, 0.3)';
  261. setTimeout(() => {
  262. btn.style.backgroundColor = 'rgba(255,255,255,0.2)';
  263. }, 200);
  264. }
  265. // Settings button function
  266. function settingsHint() {
  267. const btn = document.getElementById('settings-btn');
  268. btn.style.borderBottomColor = 'rgba(100, 200, 255, 0.4)';
  269. setTimeout(() => {
  270. btn.style.borderBottomColor = 'transparent';
  271. }, 200);
  272. }
  273. // Daily task system
  274. let taskCount = 0;
  275. const taskElements = {
  276. badge: document.querySelector('.task-badge'),
  277. counter: document.querySelector('.task-counter')
  278. };
  279. function showTaskReminder() {
  280. taskElements.badge.style.display = 'block';
  281. setTimeout(() => {
  282. taskElements.badge.style.display = 'none';
  283. }, 2000);
  284. }
  285. function dailyTaskHint() {
  286. const btn = document.getElementById('task-btn');
  287. // Button animation
  288. btn.style.transform = 'scale(0.96)';
  289. setTimeout(() => {
  290. btn.style.transform = 'scale(1)';
  291. }, 150);
  292. // Update progress
  293. taskCount = (taskCount + 1) % 4;
  294. // Completion effect
  295. if(taskCount === 3) {
  296. showTaskReminder();
  297. setTimeout(() => {
  298. taskCount = 0;
  299. }, 1000);
  300. }
  301. }
  302. // Initialize task reminder (every 30 seconds)
  303. setInterval(showTaskReminder, 30000);
  304. // Corner trigger right-click control
  305. document.getElementById('corner-trigger').addEventListener('contextmenu', (e) => {
  306. e.preventDefault();
  307. const panel = document.getElementById('settings-panel');
  308. panel.style.display = panel.style.display === 'flex' ? 'none' : 'flex';
  309. });
  310. // System button click
  311. document.getElementById('system-btn').addEventListener('click', function(e) {
  312. createRipple(e);
  313. systemHint();
  314. });
  315. // Hide menu when clicking outside
  316. document.addEventListener('click', (e) => {
  317. if (!e.target.closest('#settings-panel') &&
  318. !e.target.closest('#corner-trigger') &&
  319. !e.target.closest('#system-btn')) {
  320. document.getElementById('settings-panel').style.display = 'none';
  321. }
  322. });
  323. // Button event listeners
  324. document.getElementById('scale-btn').addEventListener('click', function(e) {
  325. createRipple(e);
  326. toggleScale();
  327. });
  328. document.getElementById('assistant-btn').addEventListener('click', function(e) {
  329. createRipple(e);
  330. assistantHint();
  331. });
  332. document.getElementById('task-btn').addEventListener('click', function(e) {
  333. createRipple(e);
  334. dailyTaskHint();
  335. });
  336. document.getElementById('settings-btn').addEventListener('click', function(e) {
  337. createRipple(e);
  338. settingsHint();
  339. });
  340. // Drag functionality
  341. let offsetX, offsetY;
  342. let longPressTimer;
  343. let dragAnimation;
  344. const LONG_PRESS_DELAY = 300;
  345. container.addEventListener('mousedown', (e) => {
  346. // Prevent text selection during drag
  347. e.preventDefault();
  348. longPressTimer = setTimeout(() => {
  349. isDragging = true;
  350. clearInterval(idleAnimation);
  351. const containerRect = container.getBoundingClientRect();
  352. // Calculate offset to position cursor at 1/4 from top and 1/2 from left
  353. offsetX = e.clientX - containerRect.left - containerRect.width / 2;
  354. offsetY = e.clientY - containerRect.top - containerRect.height / 4;
  355. // Adjust the container position
  356. container.style.left = (e.clientX - offsetX) + 'px';
  357. container.style.top = (e.clientY - offsetY) + 'px';
  358. container.style.bottom = 'auto';
  359. container.style.transform = `scale(${currentScale})`;
  360. container.style.cursor = 'grabbing';
  361. dragFrameIndex = 0;
  362. dragAnimation = setInterval(() => {
  363. petImage.src = dragFrames[dragFrameIndex];
  364. dragFrameIndex = (dragFrameIndex + 1) % dragFrames.length;
  365. }, 100);
  366. document.addEventListener('mousemove', drag);
  367. }, LONG_PRESS_DELAY);
  368. });
  369. document.addEventListener('mouseup', () => {
  370. clearTimeout(longPressTimer);
  371. if (isDragging) {
  372. isDragging = false;
  373. clearInterval(dragAnimation);
  374. startIdleAnimation();
  375. document.removeEventListener('mousemove', drag);
  376. container.style.cursor = 'pointer';
  377. }
  378. });
  379. function drag(e) {
  380. if (isDragging) {
  381. e.preventDefault();
  382. container.style.left = (e.clientX - offsetX) + 'px';
  383. container.style.top = (e.clientY - offsetY) + 'px';
  384. }
  385. }
  386. // Reset to original position function (if needed)
  387. function resetPosition() {
  388. container.style.bottom = originalPosition.bottom;
  389. container.style.left = originalPosition.left;
  390. container.style.top = 'auto';
  391. container.style.transform = originalPosition.transform;
  392. }
  393. </script>
  394. </body>
  395. </html>