webgal-engine 4.5.17 → 4.5.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/assets/OPPOSans-R-tAcFw8I3.ttf.gz +0 -0
  2. package/dist/assets/{LXGWWenKai-Regular-9375313a.ttf → ResourceHanRoundedCN-Regular-C1HdCLVq.ttf} +0 -0
  3. package/dist/assets/ResourceHanRoundedCN-Regular-C1HdCLVq.ttf.gz +0 -0
  4. package/dist/assets/SourceHanSerifCN-Regular-B_f-kQ2u.ttf.gz +0 -0
  5. package/dist/assets/conentsCash-BBWvsVB4.js +1 -0
  6. package/dist/assets/index-CkOq6uhz.css +1 -0
  7. package/dist/assets/index-CkOq6uhz.css.gz +0 -0
  8. package/dist/assets/index-MdzLVmuf.js +4137 -0
  9. package/dist/assets/index-MdzLVmuf.js.gz +0 -0
  10. package/dist/assets/{index.es-7d7e6d15.js → index.es-BeRKt7_j.js} +4 -4
  11. package/dist/assets/index.es-BeRKt7_j.js.gz +0 -0
  12. package/dist/assets/{initRegister-fdb36053.js → initRegister-xwJOf8RF.js} +1 -1
  13. package/dist/assets/initRegister-xwJOf8RF.js.gz +0 -0
  14. package/dist/index.html +136 -43
  15. package/dist/webgal-serviceworker.js +81 -58
  16. package/package.json +8 -8
  17. package/dist/assets/LXGWWenKai-Regular-9375313a.ttf.gz +0 -0
  18. package/dist/assets/OPPOSans-R-ea925359.ttf.gz +0 -0
  19. package/dist/assets/SourceHanSerifCN-Regular-1e60cc2e.ttf.gz +0 -0
  20. package/dist/assets/conentsCash-75763c1a.js +0 -1
  21. package/dist/assets/index-49446313.js +0 -4133
  22. package/dist/assets/index-49446313.js.gz +0 -0
  23. package/dist/assets/index-52a967b4.css +0 -1
  24. package/dist/assets/index-52a967b4.css.gz +0 -0
  25. package/dist/assets/index.es-7d7e6d15.js.gz +0 -0
  26. package/dist/assets/initRegister-fdb36053.js.gz +0 -0
  27. /package/dist/assets/{OPPOSans-R-ea925359.ttf → OPPOSans-R-tAcFw8I3.ttf} +0 -0
  28. /package/dist/assets/{SourceHanSerifCN-Regular-1e60cc2e.ttf → SourceHanSerifCN-Regular-B_f-kQ2u.ttf} +0 -0
  29. /package/dist/assets/{dialog-d5b91235.mp3 → dialog-BDvwibdp.mp3} +0 -0
  30. /package/dist/assets/{page-flip-1-7df32409.mp3 → page-flip-1-CZ8VQh4O.mp3} +0 -0
  31. /package/dist/assets/{switch-1-99b576bc.mp3 → switch-1-DI-7VpPw.mp3} +0 -0
@@ -1 +1 @@
1
- import{r as B,W as z,C as D,b as G,a as N,S as U,c as R,B as O,R as X}from"./index-49446313.js";const $=(b,W,k,v,E,M,m)=>{const w=z.gameplay.pixiStage,x=W==="foreground"?w.foregroundEffectsContainer:w.backgroundEffectsContainer,p=R.width,a=R.height,c=new D;c.angle=m;const C=c.rotation,y=Math.abs(Math.cos(C)),d=Math.abs(Math.sin(C)),i=p*y+a*d,f=p*d+a*y;c.width=i,c.height=f,c.pivot.set(i/2,f/2),c.position.set(p/2,a/2),x.addChild(c);const r=new G(E,{scale:!0,position:!0,rotation:!0,uvs:!1,alpha:!0});c.addChild(r);const u=[],I=N.from("./game/tex/cherryBlossoms.webp"),S=(h,l)=>h+Math.random()*(l-h);for(let h=0;h<E;h++){const l=Math.random()*Math.PI*2,n=U.from(I);n.anchor.set(.5),n.x=Math.random()*i,n.y=Math.random()*f,n.rotation=Math.random()*Math.PI*2,n.scale.set(Math.cos(l)*M,Math.sin(l)*M),n.speed=(S(.5,2)+S(.1,1))*k,n.rotationSpeed=Math.random()*.015*(Math.random()<.5?1:-1),n.positionPhase=Math.random()*Math.PI*2,n.scalePhase=l,u.push(n),r.addChild(n)}function A(h){const l=Date.now()/1e3;for(const n of u){const P=Math.sin(l+n.positionPhase)*v;n.x+=P*h,n.y+=n.speed*h,n.rotation+=n.rotationSpeed*h;const H=Math.cos(l+n.scalePhase)*M,F=Math.sin(l+n.scalePhase)*M;n.scale.set(H,F);const T=Math.abs(n.width*M),t=Math.abs(n.height*M);n.x+T/2<-i?n.x=i+T/2:n.x-T/2>i&&(n.x=-i-T/2),n.y-t/2>f&&(n.x=Math.random()*i,n.y=-Math.random()*50-t,n.positionPhase=Math.random()*Math.PI*2,n.scalePhase=Math.random()*Math.PI*2,n.speed=(S(.5,2)+S(.1,1))*k,n.rotationSpeed=Math.random()*.015*(Math.random()<.5?1:-1))}}return w.registerAnimation({setStartState:()=>{},setEndState:()=>{},tickerFunc:A},b),{container:c,tickerKey:b}};B("cherryBlossoms",{fg:()=>$("cherry-blossoms-foreground-ticker","foreground",2,3,100,.05,0),bg:()=>$("cherry-blossoms-background-ticker","background",1,2,300,.025,0)});const L=(b,W,k,v,E,M)=>{const m=z.gameplay.pixiStage;m.currentApp;const w=W==="foreground"?m.foregroundEffectsContainer:m.backgroundEffectsContainer,x=R.width,p=R.height,a=new D;a.angle=M;const c=a.rotation,C=Math.abs(Math.cos(c)),y=Math.abs(Math.sin(c)),d=x*C+p*y,i=x*y+p*C;a.width=d,a.height=i,a.pivot.set(d/2,i/2),a.position.set(x/2,p/2),w.addChild(a);const f=new G(v,{scale:!0,position:!0,rotation:!0,alpha:!0,uvs:!1});a.addChild(f);const r=[],u=[],I="./game/tex/rain.png",S=128,A=640,h=5,l=[10,5,2,2,1],n=t=>{if(!t||t.length===0)return 0;const e=t.reduce((o,g)=>o+g,0);if(e<=0)return Math.floor(Math.random()*t.length);let s=Math.random()*e;for(let o=0;o<t.length;o++){if(s<t[o])return o;s-=t[o]}return t.length-1},P=(t,e=!1)=>{const s=Math.random()*.5+.5;t.scale.set(E*s),t.anchor.set(.5),e?(t.x=Math.random()*d,t.y=Math.random()*i):(t.x=Math.random()*d,t.y=-Math.random()*50-t.height),t.alpha=Math.random()*.5+.5,t.vy=(Math.random()*.4+.8)*k},H=()=>{let t;r.length===h?t=n(l):t=Math.floor(Math.random()*r.length),t=Math.max(0,Math.min(t,r.length-1));const e=new U(r[t]);return P(e,!0),e},F=t=>{for(const e of u)e.y+=e.vy*t,(e.y-e.height/2>i||e.x<-e.width||e.x>d+e.width)&&P(e,!1)};return(()=>{for(r.length=0;u.length>0;)u.pop();f.removeChildren();const t=O.from(I),e=()=>{var s;if(t.valid)for(let o=0;o<h;o++){const g=new X(o*S,0,S,A);r.push(new N(t,g))}if(r.length===0){console.error("Failed to create any raindrop textures. Cannot create sprites.");return}(s=r[0])!=null&&s.valid||console.warn("First raindrop texture is invalid after creation. Sprites might not render correctly.");for(let o=0;o<v;o++){const g=H();f.addChild(g),u.push(g)}m.registerAnimation({setStartState:()=>{},setEndState:()=>{},tickerFunc:F},b)};t.valid?e():(t.once("loaded",()=>{e()}),t.once("error",s=>{console.error(`Error loading base texture ${I}:`,s),e()}))})(),{container:a,tickerKey:b}};B("rain",{fg:()=>L("rain-foreground-ticker","foreground",30,50,.4,1),bg:()=>L("rain-background-ticker","background",20,150,.3,1)});const _=(b,W,k,v,E,M)=>{const m=z.gameplay.pixiStage;m.currentApp;const w=W==="foreground"?m.foregroundEffectsContainer:m.backgroundEffectsContainer,x=R.width,p=R.height,a=new D;a.angle=M;const c=a.rotation,C=Math.abs(Math.cos(c)),y=Math.abs(Math.sin(c)),d=x*C+p*y,i=x*y+p*C;a.width=d,a.height=i,a.pivot.set(d/2,i/2),a.position.set(x/2,p/2),w.addChild(a);const f=new G(v,{scale:!0,position:!0,rotation:!0,alpha:!0,uvs:!1});a.addChild(f);const r=[],u=[],I="./game/tex/snow.png",S=128,A=128,h=10,l=[10,2,2,2,1,1,1,2,2,2],n=t=>{if(!t||t.length===0)return 0;const e=t.reduce((o,g)=>o+g,0);if(e<=0)return Math.floor(Math.random()*t.length);let s=Math.random()*e;for(let o=0;o<t.length;o++){if(s<t[o])return o;s-=t[o]}return t.length-1},P=(t,e=!1)=>{const s=Math.random()*.5+.5;t.scale.set(E*s),t.anchor.set(.5),e?(t.x=Math.random()*d,t.y=Math.random()*i):(t.x=Math.random()*d,t.y=-Math.random()*50-t.height),t.alpha=Math.random()*.2+.8,t.vy=(Math.random()*.4+.8)*k,t.vx=(Math.random()-.5)*.25*k,t.rotationSpeed=(Math.random()-.5)*.005},H=()=>{let t;r.length===h?t=n(l):t=Math.floor(Math.random()*r.length),t=Math.max(0,Math.min(t,r.length-1));const e=new U(r[t]);return P(e,!0),e},F=t=>{for(const e of u)e.y+=e.vy*t,e.x+=e.vx*t,e.rotation+=e.rotationSpeed*t,(e.y-e.height/2>i||e.x<-e.width||e.x>d+e.width)&&P(e,!1)};return(()=>{for(r.length=0;u.length>0;)u.pop();f.removeChildren();const t=O.from(I),e=()=>{var s;if(t.valid)for(let o=0;o<h;o++){const g=new X(o*S,0,S,A);r.push(new N(t,g))}if(r.length===0){console.error("Failed to create any snowflake textures. Cannot create sprites.");return}(s=r[0])!=null&&s.valid||console.warn("First snowflake texture is invalid after creation. Sprites might not render correctly.");for(let o=0;o<v;o++){const g=H();f.addChild(g),u.push(g)}m.registerAnimation({setStartState:()=>{},setEndState:()=>{},tickerFunc:F},b)};t.valid?e():(t.once("loaded",()=>{e()}),t.once("error",s=>{console.error(`Error loading base texture ${I}:`,s),e()}))})(),{container:a,tickerKey:b}};B("snow",{fg:()=>_("snow-foreground-ticker","foreground",3,250,.4,0),bg:()=>_("snow-background-ticker","background",1,750,.2,0)});B("heavySnow",{fg:()=>_("heavy-snow-foreground-ticker","foreground",20,1e3,.6,-75),bg:()=>_("heavy-snow-background-ticker","background",10,2e3,.3,-80)});
1
+ import{r as B,W as z,C as D,b as G,a as N,S as U,c as R,B as O,R as X}from"./index-MdzLVmuf.js";const $=(b,W,k,v,E,M,m)=>{const w=z.gameplay.pixiStage,x=W==="foreground"?w.foregroundEffectsContainer:w.backgroundEffectsContainer,p=R.width,a=R.height,c=new D;c.angle=m;const C=c.rotation,y=Math.abs(Math.cos(C)),d=Math.abs(Math.sin(C)),i=p*y+a*d,f=p*d+a*y;c.width=i,c.height=f,c.pivot.set(i/2,f/2),c.position.set(p/2,a/2),x.addChild(c);const r=new G(E,{scale:!0,position:!0,rotation:!0,uvs:!1,alpha:!0});c.addChild(r);const u=[],I=N.from("./game/tex/cherryBlossoms.webp"),S=(h,l)=>h+Math.random()*(l-h);for(let h=0;h<E;h++){const l=Math.random()*Math.PI*2,n=U.from(I);n.anchor.set(.5),n.x=Math.random()*i,n.y=Math.random()*f,n.rotation=Math.random()*Math.PI*2,n.scale.set(Math.cos(l)*M,Math.sin(l)*M),n.speed=(S(.5,2)+S(.1,1))*k,n.rotationSpeed=Math.random()*.015*(Math.random()<.5?1:-1),n.positionPhase=Math.random()*Math.PI*2,n.scalePhase=l,u.push(n),r.addChild(n)}function A(h){const l=Date.now()/1e3;for(const n of u){const P=Math.sin(l+n.positionPhase)*v;n.x+=P*h,n.y+=n.speed*h,n.rotation+=n.rotationSpeed*h;const H=Math.cos(l+n.scalePhase)*M,F=Math.sin(l+n.scalePhase)*M;n.scale.set(H,F);const T=Math.abs(n.width*M),t=Math.abs(n.height*M);n.x+T/2<-i?n.x=i+T/2:n.x-T/2>i&&(n.x=-i-T/2),n.y-t/2>f&&(n.x=Math.random()*i,n.y=-Math.random()*50-t,n.positionPhase=Math.random()*Math.PI*2,n.scalePhase=Math.random()*Math.PI*2,n.speed=(S(.5,2)+S(.1,1))*k,n.rotationSpeed=Math.random()*.015*(Math.random()<.5?1:-1))}}return w.registerAnimation({setStartState:()=>{},setEndState:()=>{},tickerFunc:A},b),{container:c,tickerKey:b}};B("cherryBlossoms",{fg:()=>$("cherry-blossoms-foreground-ticker","foreground",2,3,100,.05,0),bg:()=>$("cherry-blossoms-background-ticker","background",1,2,300,.025,0)});const L=(b,W,k,v,E,M)=>{const m=z.gameplay.pixiStage;m.currentApp;const w=W==="foreground"?m.foregroundEffectsContainer:m.backgroundEffectsContainer,x=R.width,p=R.height,a=new D;a.angle=M;const c=a.rotation,C=Math.abs(Math.cos(c)),y=Math.abs(Math.sin(c)),d=x*C+p*y,i=x*y+p*C;a.width=d,a.height=i,a.pivot.set(d/2,i/2),a.position.set(x/2,p/2),w.addChild(a);const f=new G(v,{scale:!0,position:!0,rotation:!0,alpha:!0,uvs:!1});a.addChild(f);const r=[],u=[],I="./game/tex/rain.png",S=128,A=640,h=5,l=[10,5,2,2,1],n=t=>{if(!t||t.length===0)return 0;const e=t.reduce((o,g)=>o+g,0);if(e<=0)return Math.floor(Math.random()*t.length);let s=Math.random()*e;for(let o=0;o<t.length;o++){if(s<t[o])return o;s-=t[o]}return t.length-1},P=(t,e=!1)=>{const s=Math.random()*.5+.5;t.scale.set(E*s),t.anchor.set(.5),e?(t.x=Math.random()*d,t.y=Math.random()*i):(t.x=Math.random()*d,t.y=-Math.random()*50-t.height),t.alpha=Math.random()*.5+.5,t.vy=(Math.random()*.4+.8)*k},H=()=>{let t;r.length===h?t=n(l):t=Math.floor(Math.random()*r.length),t=Math.max(0,Math.min(t,r.length-1));const e=new U(r[t]);return P(e,!0),e},F=t=>{for(const e of u)e.y+=e.vy*t,(e.y-e.height/2>i||e.x<-e.width||e.x>d+e.width)&&P(e,!1)};return(()=>{for(r.length=0;u.length>0;)u.pop();f.removeChildren();const t=O.from(I),e=()=>{var s;if(t.valid)for(let o=0;o<h;o++){const g=new X(o*S,0,S,A);r.push(new N(t,g))}if(r.length===0){console.error("Failed to create any raindrop textures. Cannot create sprites.");return}(s=r[0])!=null&&s.valid||console.warn("First raindrop texture is invalid after creation. Sprites might not render correctly.");for(let o=0;o<v;o++){const g=H();f.addChild(g),u.push(g)}m.registerAnimation({setStartState:()=>{},setEndState:()=>{},tickerFunc:F},b)};t.valid?e():(t.once("loaded",()=>{e()}),t.once("error",s=>{console.error(`Error loading base texture ${I}:`,s),e()}))})(),{container:a,tickerKey:b}};B("rain",{fg:()=>L("rain-foreground-ticker","foreground",30,50,.4,1),bg:()=>L("rain-background-ticker","background",20,150,.3,1)});const _=(b,W,k,v,E,M)=>{const m=z.gameplay.pixiStage;m.currentApp;const w=W==="foreground"?m.foregroundEffectsContainer:m.backgroundEffectsContainer,x=R.width,p=R.height,a=new D;a.angle=M;const c=a.rotation,C=Math.abs(Math.cos(c)),y=Math.abs(Math.sin(c)),d=x*C+p*y,i=x*y+p*C;a.width=d,a.height=i,a.pivot.set(d/2,i/2),a.position.set(x/2,p/2),w.addChild(a);const f=new G(v,{scale:!0,position:!0,rotation:!0,alpha:!0,uvs:!1});a.addChild(f);const r=[],u=[],I="./game/tex/snow.png",S=128,A=128,h=10,l=[10,2,2,2,1,1,1,2,2,2],n=t=>{if(!t||t.length===0)return 0;const e=t.reduce((o,g)=>o+g,0);if(e<=0)return Math.floor(Math.random()*t.length);let s=Math.random()*e;for(let o=0;o<t.length;o++){if(s<t[o])return o;s-=t[o]}return t.length-1},P=(t,e=!1)=>{const s=Math.random()*.5+.5;t.scale.set(E*s),t.anchor.set(.5),e?(t.x=Math.random()*d,t.y=Math.random()*i):(t.x=Math.random()*d,t.y=-Math.random()*50-t.height),t.alpha=Math.random()*.2+.8,t.vy=(Math.random()*.4+.8)*k,t.vx=(Math.random()-.5)*.25*k,t.rotationSpeed=(Math.random()-.5)*.005},H=()=>{let t;r.length===h?t=n(l):t=Math.floor(Math.random()*r.length),t=Math.max(0,Math.min(t,r.length-1));const e=new U(r[t]);return P(e,!0),e},F=t=>{for(const e of u)e.y+=e.vy*t,e.x+=e.vx*t,e.rotation+=e.rotationSpeed*t,(e.y-e.height/2>i||e.x<-e.width||e.x>d+e.width)&&P(e,!1)};return(()=>{for(r.length=0;u.length>0;)u.pop();f.removeChildren();const t=O.from(I),e=()=>{var s;if(t.valid)for(let o=0;o<h;o++){const g=new X(o*S,0,S,A);r.push(new N(t,g))}if(r.length===0){console.error("Failed to create any snowflake textures. Cannot create sprites.");return}(s=r[0])!=null&&s.valid||console.warn("First snowflake texture is invalid after creation. Sprites might not render correctly.");for(let o=0;o<v;o++){const g=H();f.addChild(g),u.push(g)}m.registerAnimation({setStartState:()=>{},setEndState:()=>{},tickerFunc:F},b)};t.valid?e():(t.once("loaded",()=>{e()}),t.once("error",s=>{console.error(`Error loading base texture ${I}:`,s),e()}))})(),{container:a,tickerKey:b}};B("snow",{fg:()=>_("snow-foreground-ticker","foreground",3,250,.4,0),bg:()=>_("snow-background-ticker","background",1,750,.2,0)});B("heavySnow",{fg:()=>_("heavy-snow-foreground-ticker","foreground",20,1e3,.6,-75),bg:()=>_("heavy-snow-background-ticker","background",10,2e3,.3,-80)});
package/dist/index.html CHANGED
@@ -7,6 +7,15 @@
7
7
  <link rel="manifest" href="./manifest.json" />
8
8
  <title>WebGAL</title>
9
9
  <style>
10
+ html,
11
+ body {
12
+ margin: 0;
13
+ background: black;
14
+ width: 100%;
15
+ height: 100%;
16
+ overflow: hidden;
17
+ }
18
+
10
19
  .html-body__effect-background {
11
20
  height: 100vh;
12
21
  width: 100vw;
@@ -17,6 +26,20 @@
17
26
  position: absolute;
18
27
  top: 0;
19
28
  left: 0;
29
+ background-color: black;
30
+ }
31
+
32
+ .html-body__effect-background-overlay {
33
+ height: 100%;
34
+ width: 100%;
35
+ background-position: center;
36
+ background-repeat: no-repeat;
37
+ background-size: cover;
38
+ position: absolute;
39
+ top: 0;
40
+ left: 0;
41
+ background-color: black;
42
+ opacity: 0;
20
43
  }
21
44
 
22
45
  .html-body__title-enter {
@@ -111,13 +134,16 @@
111
134
  .title-enter-container__link-to-github > div {
112
135
  padding: 0 0 0.25em 0;
113
136
  }
137
+
114
138
  </style>
115
- <script type="module" crossorigin src="./assets/index-49446313.js"></script>
116
- <link rel="stylesheet" href="./assets/index-52a967b4.css">
139
+ <script type="module" crossorigin src="./assets/index-MdzLVmuf.js"></script>
140
+ <link rel="stylesheet" crossorigin href="./assets/index-CkOq6uhz.css">
117
141
  </head>
118
142
  <body>
119
143
  <!-- 背景模糊 -->
120
- <div class="html-body__effect-background"></div>
144
+ <div id="ebg" class="html-body__effect-background">
145
+ <div id="ebgOverlay" class="html-body__effect-background-overlay"></div>
146
+ </div>
121
147
  <!-- 落地页 -->
122
148
  <div class="html-body__title-enter">
123
149
  <div class="title-enter__initial-background"></div>
@@ -135,29 +161,70 @@
135
161
  <div id="html-body__panic-overlay"></div>
136
162
  <!-- 应用挂载点 -->
137
163
  <div id="root"></div>
164
+ <script>
165
+ (() => {
166
+ const userAgent = navigator.userAgent || '';
167
+ const platform = navigator.userAgentData?.platform || navigator.platform || '';
168
+ const maxTouchPoints = navigator.maxTouchPoints || 0;
169
+ const isIOSPhone = /iPhone|iPod/i.test(userAgent);
170
+ const isIPad = /iPad/i.test(userAgent) || (/Mac/i.test(platform) && maxTouchPoints > 1);
171
+
172
+ window.__WEBGAL_DEVICE_INFO__ = {
173
+ isIOS: isIOSPhone || isIPad,
174
+ isIOSPhone,
175
+ isIPad,
176
+ };
177
+ })();
178
+ </script>
138
179
  <!-- 在窗口大小改变时进行强制缩放 -->
139
180
  <script>
140
181
  (() => {
141
- const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
182
+ const deviceInfo = window.__WEBGAL_DEVICE_INFO__ ?? { isIOS: false };
183
+ const isIOS = deviceInfo.isIOS;
184
+ const layoutConfig = isIOS
185
+ ? {
186
+ bottomInset: 15,
187
+ resizeDelay: 500,
188
+ viewport:
189
+ 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover',
190
+ hideEffectBackground: true,
191
+ }
192
+ : {
193
+ bottomInset: 0,
194
+ resizeDelay: 0,
195
+ viewport: 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no',
196
+ hideEffectBackground: false,
197
+ };
198
+ const root = document.querySelector('#root');
199
+ const titleEnter = document.querySelector('.html-body__title-enter');
200
+ const effectBackground = document.querySelector('.html-body__effect-background');
201
+ let viewportMeta = document.querySelector('meta[name="viewport"]');
202
+
203
+ const ensureViewportMeta = () => {
204
+ if (!viewportMeta) {
205
+ viewportMeta = document.createElement('meta');
206
+ viewportMeta.name = 'viewport';
207
+ document.head.appendChild(viewportMeta);
208
+ }
209
+ return viewportMeta;
210
+ };
211
+
142
212
  const resize = () => {
143
213
  const targetHeight = 1440; // 目标高度
144
214
  const targetWidth = 2560; // 目标宽度
145
-
146
215
  const h = window.innerHeight; // 窗口高度
147
216
  const w = window.innerWidth; // 窗口宽度
148
- const zoomH = h / targetHeight; // 以窗口高度为基准的变换比
217
+ const layoutHeight = Math.max(h - layoutConfig.bottomInset, 1);
218
+ const zoomH = layoutHeight / targetHeight; // 以窗口高度为基准的变换比
149
219
  const zoomW = w / targetWidth; // 以窗口宽度为基准的变换比
150
220
  const zoomH2 = w / targetHeight; // 竖屏时以窗口高度为基础的变换比
151
- const zoomW2 = h / targetWidth; // 竖屏时以窗口宽度为基础的变换比
152
- let mh = (targetHeight - h) / 2; // y轴移动距离
221
+ const zoomW2 = layoutHeight / targetWidth; // 竖屏时以窗口宽度为基础的变换比
222
+ let mh = (targetHeight - layoutHeight) / 2; // y轴移动距离
153
223
  let mw = (targetWidth - w) / 2; // x轴移动距离
154
224
  let mh2os = targetWidth / 2 - w / 2; // 竖屏时 y轴移动距离
155
- let mw2os = targetHeight / 2 - h / 2; // 竖屏时 x轴移动距离
225
+ let mw2os = targetHeight / 2 - layoutHeight / 2; // 竖屏时 x轴移动距离
156
226
  let transform = '';
157
227
  let effectBackgroundTransform = '';
158
- const root = document.querySelector('#root'); // 获取根元素
159
- const titleEnter = document.querySelector('.html-body__title-enter');
160
- const effectBackground = document.querySelector('.html-body__effect-background');
161
228
  const elements = [root, titleEnter];
162
229
  if (w > h) {
163
230
  if (effectBackground) {
@@ -193,6 +260,11 @@
193
260
  // iOS 不强制旋转
194
261
  if (isIOS) {
195
262
  const zoomWi = w / targetWidth;
263
+ if (effectBackground) {
264
+ effectBackground.style.height = `100vh`;
265
+ effectBackground.style.width = `100vw`;
266
+ effectBackgroundTransform = '';
267
+ }
196
268
  transform = `translate(${-mw}px, ${-mh}px) ` + `scale(${zoomWi},${zoomWi}) `;
197
269
  }
198
270
  }
@@ -205,42 +277,51 @@
205
277
  }
206
278
  }
207
279
  };
208
- if (!isIOS) {
209
- // 非 IOS
210
- // 创建一个新的 meta 标签
211
- const metaTag = document.createElement('meta');
212
- metaTag.name = 'viewport';
213
- metaTag.content = 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no';
214
- // 将该标签添加到 head 中
215
- document.head.appendChild(metaTag);
216
- resize();
217
- window.onload = resize;
218
- window.onresize = resize;
219
- // 监听键盘 F11 键按下事件,全屏时触发页面调整
220
- document.onkeydown = (e) => {
221
- if (e && e.key === 'F11') {
222
- setTimeout(() => {
223
- resize();
224
- }, 100);
280
+ let iosResizeTimer = null;
281
+ const scheduleResize = () => {
282
+ if (layoutConfig.resizeDelay > 0) {
283
+ if (iosResizeTimer) {
284
+ window.clearTimeout(iosResizeTimer);
225
285
  }
226
- };
227
- } else {
228
- // IOS
229
- const metaTag = document.createElement('meta');
230
- metaTag.name = 'viewport';
231
- metaTag.content = 'width=device-width, initial-scale=0.22, minimum-scale=0.01, maximum-scale=1';
232
- // 将该标签添加到 head 中
233
- document.head.appendChild(metaTag);
286
+ iosResizeTimer = window.setTimeout(() => {
287
+ resize();
288
+ iosResizeTimer = null;
289
+ }, layoutConfig.resizeDelay);
290
+ return;
291
+ }
292
+ resize();
293
+ };
294
+ if (isIOS) {
234
295
  const styleTag = document.createElement('style');
235
- styleTag.textContent = '* { font-synthesis: none !important; }';
296
+ styleTag.textContent = `* { font-synthesis: none !important; }`;
297
+ if (layoutConfig.hideEffectBackground) {
298
+ styleTag.textContent += `
299
+ #ebg,
300
+ #ebgOverlay {
301
+ display: none !important;
302
+ }
303
+ `;
304
+ }
236
305
  document.head.appendChild(styleTag);
237
306
  }
307
+ ensureViewportMeta().content = layoutConfig.viewport;
308
+ scheduleResize();
309
+ window.onload = scheduleResize;
310
+ window.onresize = scheduleResize;
311
+ // 监听键盘 F11 键按下事件,全屏时触发页面调整
312
+ document.onkeydown = (e) => {
313
+ if (e && e.key === 'F11') {
314
+ setTimeout(() => {
315
+ scheduleResize();
316
+ }, 100);
317
+ }
318
+ };
238
319
  })();
239
320
  </script>
240
321
  <!-- 注册 Service Worker -->
241
322
  <script>
242
323
  (() => {
243
- const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
324
+ const isIOS = window.__WEBGAL_DEVICE_INFO__?.isIOS ?? false;
244
325
  if ('serviceWorker' in navigator && !isIOS) {
245
326
  navigator.serviceWorker
246
327
  .register('./webgal-serviceworker.js')
@@ -256,7 +337,10 @@
256
337
  <!-- 首屏加载 -->
257
338
  <script>
258
339
  (() => {
259
- const isIOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
340
+ const isIOS = window.__WEBGAL_DEVICE_INFO__?.isIOS ?? false;
341
+ const enterConfig = isIOS
342
+ ? { skipAnimation: true, hideDelay: 0 }
343
+ : { skipAnimation: false, hideDelay: 2000 };
260
344
  let enterPromiseResolve;
261
345
  const enterPromise = new Promise((res) => {
262
346
  enterPromiseResolve = res;
@@ -281,6 +365,17 @@
281
365
  });
282
366
  /** 点击屏幕,进入引擎主界面 */
283
367
  const enter = () => {
368
+ const titleEnter = document.querySelector('.html-body__title-enter');
369
+ if (enterConfig.skipAnimation) {
370
+ if (titleEnter) {
371
+ titleEnter.style.pointerEvents = 'none';
372
+ titleEnter.style.transition = 'none';
373
+ titleEnter.style.opacity = '0';
374
+ titleEnter.style.display = 'none';
375
+ }
376
+ enterPromiseResolve();
377
+ return;
378
+ }
284
379
  const initialBackground = document.querySelector('.title-enter__initial-background');
285
380
  if (initialBackground) {
286
381
  initialBackground.style.opacity = '0';
@@ -295,7 +390,6 @@
295
390
  whiteBackground.style.opacity = '1';
296
391
  }
297
392
  }, 50); // 在50ms后开始显示白色渐变
298
- const titleEnter = document.querySelector('.html-body__title-enter');
299
393
  setTimeout(() => {
300
394
  if (titleEnter) titleEnter.style.opacity = '0';
301
395
  }, 500); // 500ms后开始降低落地页透明度
@@ -307,7 +401,7 @@
307
401
  if (titleEnter) {
308
402
  titleEnter.style.display = 'none';
309
403
  }
310
- }, 2000); // 将落地页设置为不显示
404
+ }, enterConfig.hideDelay); // 将落地页设置为不显示
311
405
  enterPromiseResolve();
312
406
  };
313
407
  const titleEnter = document.querySelector('.html-body__title-enter');
@@ -360,6 +454,5 @@
360
454
  })();
361
455
  </script>
362
456
  <!-- main文件 -->
363
-
364
457
  </body>
365
458
  </html>
@@ -1,63 +1,86 @@
1
- self.addEventListener('install', (ev) => {
2
- // console.log('[service worker] installing');
3
- ev.waitUntil(self.skipWaiting());
1
+ const CACHE_NAME = 'webgal-critical-assets-v3';
2
+ const GAME_PREFIX = '/game/';
3
+ const CRITICAL_PATHS = ['/game/background/', '/game/figure/', '/game/bgm/', '/game/vocal/', '/game/video/'];
4
+ const LOG_PREFIX = '[WebGAL SW]';
5
+ const loggedKeys = new Set();
6
+
7
+ function logOnce(key, ...args) {
8
+ if (loggedKeys.has(key)) return;
9
+ loggedKeys.add(key);
10
+ console.log(LOG_PREFIX, ...args);
11
+ }
12
+
13
+ self.addEventListener('install', (event) => {
14
+ logOnce('install', `install ${CACHE_NAME}`);
15
+ event.waitUntil(self.skipWaiting());
16
+ });
17
+
18
+ self.addEventListener('activate', (event) => {
19
+ logOnce('activate', `activate ${CACHE_NAME}`);
20
+ event.waitUntil(
21
+ (async () => {
22
+ const keys = await caches.keys();
23
+ await Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)));
24
+ await self.clients.claim();
25
+ })(),
26
+ );
4
27
  });
5
28
 
6
- // fetch事件是每次页面请求资源时触发的
7
- self.addEventListener('fetch', function (event) {
8
- const url = event.request.url;
9
- const isReturnCache = !!(url.match('/assets/') && !url.match('game'));
10
- if (isReturnCache) {
11
- // console.log('%cCACHED: ' + url, 'color: #005CAF; padding: 2px;');
29
+ function isCriticalGameRequest(request) {
30
+ if (request.method !== 'GET') return false;
31
+ const url = new URL(request.url);
32
+ if (url.origin !== self.location.origin) return false;
33
+ if (!url.pathname.startsWith(GAME_PREFIX)) return false;
34
+ return CRITICAL_PATHS.some((prefix) => url.pathname.startsWith(prefix));
35
+ }
36
+
37
+ // Stale-while-revalidate: return cached response immediately, then update cache in background.
38
+ async function staleWhileRevalidate(request) {
39
+ const cache = await caches.open(CACHE_NAME);
40
+ const cached = await cache.match(request.url);
41
+
42
+ const fetchAndUpdate = async () => {
43
+ try {
44
+ const response = await fetch(request);
45
+ if (response.ok) {
46
+ await cache.put(request.url, response.clone());
47
+ }
48
+ return response;
49
+ } catch (e) {
50
+ return null;
51
+ }
52
+ };
53
+
54
+ if (cached) {
55
+ logOnce(`hit:${request.url}`, 'cache hit (revalidating):', new URL(request.url).pathname);
56
+ // Revalidate in background — don't await
57
+ fetchAndUpdate();
58
+ return cached;
59
+ }
60
+
61
+ // No cache — must wait for network
62
+ const response = await fetch(request);
63
+ if (response.ok) {
64
+ await cache.put(request.url, response.clone());
65
+ logOnce(`cache:${request.url}`, 'cached:', new URL(request.url).pathname);
12
66
  }
13
- if (!isReturnCache) {
14
- event.respondWith(fetch(event.request));
15
- } else {
16
- event.respondWith(
17
- // 检查在缓存中是否有匹配的资源
18
- caches.match(event.request).then(function (response) {
19
- // 如果缓存中有匹配的资源,则返回缓存资源
20
- if (response) {
21
- return response;
22
- }
23
- // 如果没有匹配的资源,则尝试从网络请求
24
- // 同时将获取的资源存入缓存
25
- return fetch(event.request)
26
- .then(function (networkResponse) {
27
- console.log('%cCACHED: ' + url, 'color: #005CAF; padding: 2px;');
28
- if (networkResponse.status === 206 && event.request.headers.has('range')) {
29
- // 如果是部分响应且请求带有Range头,则创建新的请求,将完整响应返回给客户端
30
- // eslint-disable-next-line max-nested-callbacks
31
- return fetch(event.request.url).then(function (fullNetworkResponse) {
32
- const headers = {};
33
- for (let entry of fullNetworkResponse.headers.entries()) {
34
- headers[entry[0]] = entry[1];
35
- }
36
- const fullResponse = new Response(fullNetworkResponse.body, {
37
- status: fullNetworkResponse.status,
38
- statusText: fullNetworkResponse.statusText,
39
- headers: headers,
40
- });
41
- const clonedResponse = fullResponse.clone();
42
- // eslint-disable-next-line max-nested-callbacks
43
- caches.open('my-cache').then(function (cache) {
44
- cache.put(event.request, clonedResponse);
45
- });
46
- return fullResponse;
47
- });
48
- }
49
- const clonedResponse = networkResponse.clone();
50
- // eslint-disable-next-line max-nested-callbacks
51
- caches.open('my-cache').then(function (cache) {
52
- cache.put(event.request, clonedResponse);
53
- });
54
- return networkResponse;
55
- })
56
- .catch(function (error) {
57
- console.error('Fetching failed:', error);
58
- throw error;
59
- });
60
- }),
61
- );
67
+ return response;
68
+ }
69
+
70
+ self.addEventListener('fetch', (event) => {
71
+ const { request } = event;
72
+ if (!isCriticalGameRequest(request)) return;
73
+
74
+ // Audio/video range requests are passed through to avoid partial-content edge cases.
75
+ if (request.headers.has('range')) {
76
+ logOnce(`range:${request.url}`, 'range passthrough:', new URL(request.url).pathname);
77
+ event.respondWith(fetch(request));
78
+ return;
62
79
  }
80
+
81
+ event.respondWith(
82
+ staleWhileRevalidate(request).catch(() => {
83
+ return fetch(request);
84
+ }),
85
+ );
63
86
  });
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "webgal-engine",
3
- "version": "4.5.17",
3
+ "version": "4.5.19",
4
4
  "scripts": {
5
5
  "dev": "vite --host --port 3000",
6
- "build": "cross-env NODE_ENV=production tsc && vite build --base=./",
6
+ "build": "node scripts/update-engine-version.js && cross-env NODE_ENV=production tsc && vite build --base=./",
7
7
  "preview": "vite preview",
8
8
  "lint": "eslint src/** --fix",
9
9
  "prepublishOnly": "npm run build"
@@ -13,12 +13,12 @@
13
13
  "@icon-park/react": "^1.4.2",
14
14
  "@reduxjs/toolkit": "^1.8.1",
15
15
  "angular-expressions": "^1.4.3",
16
- "axios": "^0.30.2",
16
+ "axios": "^1.13.5",
17
17
  "cloudlogjs": "^1.0.9",
18
18
  "gifuct-js": "^2.1.2",
19
19
  "i18next": "^22.4.15",
20
20
  "localforage": "^1.10.0",
21
- "lodash": "^4.17.21",
21
+ "lodash": "^4.17.23",
22
22
  "mitt": "^3.0.0",
23
23
  "modern-css-reset": "^1.4.0",
24
24
  "pixi-filters": "^4.2.0",
@@ -39,11 +39,11 @@
39
39
  "@types/react": "^17.0.33",
40
40
  "@types/react-dom": "^17.0.10",
41
41
  "@types/uuid": "^8.3.4",
42
- "@typescript-eslint/eslint-plugin": "^5.18.0",
43
- "@typescript-eslint/parser": "^5.18.0",
42
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
43
+ "@typescript-eslint/parser": "^8.0.0",
44
44
  "@vitejs/plugin-react": "^4.0.4",
45
45
  "cross-env": "^7.0.3",
46
- "eslint": "^8.13.0",
46
+ "eslint": "^9.26.0",
47
47
  "eslint-config-alloy": "^4.5.1",
48
48
  "eslint-config-prettier": "^8.5.0",
49
49
  "eslint-plugin-prettier": "^4.2.1",
@@ -53,7 +53,7 @@
53
53
  "rollup-plugin-visualizer": "^5.6.0",
54
54
  "typescript": "^4.5.4",
55
55
  "unplugin-info": "^1.2.2",
56
- "vite": "^4.5.5",
56
+ "vite": "^5.4.21",
57
57
  "vite-plugin-compression": "^0.5.1"
58
58
  }
59
59
  }
@@ -1 +0,0 @@
1
- var e=Object.defineProperty;var c=(n,t,s)=>t in n?e(n,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):n[t]=s;var o=(n,t,s)=>(c(n,typeof t!="symbol"?t+"":t,s),s);class h{constructor(){o(this,"_content","")}push(t){this._content=t}pop(){const t=this._content;return this._content="",t}}class i{constructor(){o(this,"_content","")}push(t){this._content=t}pop(){const t=this._content;return this._content="",t}}const _=new h,p=new i;export{h as FigureConentsCash,i as VoiceConentsCash,_ as figureCash,p as voiceCash};