demo/bump v4:宝宝活在整页底下,滑到哪个模块就在哪一屏顶出小帐篷
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,16 +14,16 @@
|
|||||||
· 手指戳上去 = 肚皮被按下去一个窝,松手后 duang duang 回弹(欠阻尼弹簧)+ 周围一起晃;
|
· 手指戳上去 = 肚皮被按下去一个窝,松手后 duang duang 回弹(欠阻尼弹簧)+ 周围一起晃;
|
||||||
· 戳中鼓起处 → 被摁回去,往远离手指的方向溜走,过一两秒换个部位、换个地方再顶出来;
|
· 戳中鼓起处 → 被摁回去,往远离手指的方向溜走,过一两秒换个部位、换个地方再顶出来;
|
||||||
· 头图下方「找找宝宝」收集条:戳回过哪个部位就点亮哪个。
|
· 头图下方「找找宝宝」收集条:戳回过哪个部位就点亮哪个。
|
||||||
下面的卡片是首页截图(静态),只为给头图一个真实语境。
|
v4:宝宝活在整个页面底下——头图 + 下面所有模块(首页截图)合成一张整页纹理,WebGL 画布固定铺满屏幕,
|
||||||
|
按滚动位置取当前这一屏来画;滑到别的模块停下来,宝宝会在这一屏里慢慢顶一下,把卡片撑成小帐篷。
|
||||||
?rec=1:录屏模式,由 __adv / __tap / __press 逐帧驱动(生成动图用)。 -->
|
?rec=1:录屏模式,由 __adv / __tap / __press 逐帧驱动(生成动图用)。 -->
|
||||||
<style>
|
<style>
|
||||||
html,body{margin:0;background:#F8F3EF;-webkit-tap-highlight-color:transparent;font-family:-apple-system,"PingFang SC","Noto Sans SC",sans-serif}
|
html,body{margin:0;background:#F8F3EF;-webkit-tap-highlight-color:transparent;font-family:-apple-system,"PingFang SC","Noto Sans SC",sans-serif}
|
||||||
.page{position:relative;max-width:480px;margin:0 auto;overflow:hidden}
|
.page{position:relative;max-width:480px;margin:0 auto;overflow:hidden}
|
||||||
.hero{position:relative;width:100%;aspect-ratio:375/270;touch-action:manipulation;cursor:pointer}
|
.page img{display:block;width:100%} /* 真实排版用的静态图:撑出页面高度,WebGL 起不来时直接看它 */
|
||||||
.hero canvas,.hero img{position:absolute;inset:0;width:100%;height:100%;display:block}
|
/* 整页的「肚皮」:固定铺满一屏,按滚动位置画当前这一屏 */
|
||||||
.hero img{opacity:0} /* WebGL 起不来时退回静态头图 */
|
#cv{position:fixed;top:0;left:50%;width:min(100vw,480px);height:100%;transform:translateX(-50%);pointer-events:none;z-index:2;opacity:0}
|
||||||
.hero.nogl img{opacity:1}
|
#cv.on{opacity:1}
|
||||||
.below{display:block;width:100%;margin-top:0}
|
|
||||||
/* 头图下缘的「找找宝宝」收集条:和首页「记一下」同一套白色玻璃胶囊语言 */
|
/* 头图下缘的「找找宝宝」收集条:和首页「记一下」同一套白色玻璃胶囊语言 */
|
||||||
.hunt{position:absolute;left:0;right:0;top:0;display:flex;justify-content:center;pointer-events:none;z-index:3}
|
.hunt{position:absolute;left:0;right:0;top:0;display:flex;justify-content:center;pointer-events:none;z-index:3}
|
||||||
.hunt .bar{margin-top:calc(min(100vw,480px) * 216 / 375);display:flex;align-items:center;gap:6px;padding:6px 7px 6px 13px;border-radius:999px;
|
.hunt .bar{margin-top:calc(min(100vw,480px) * 216 / 375);display:flex;align-items:center;gap:6px;padding:6px 7px 6px 13px;border-radius:999px;
|
||||||
@@ -46,31 +46,32 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="hero" id="hero">
|
|
||||||
<img src="belly.jpg" alt="">
|
<img src="belly.jpg" alt="">
|
||||||
<canvas id="cv"></canvas>
|
<img src="below.jpg" alt="">
|
||||||
<i class="finger" id="finger"></i>
|
<i class="finger" id="finger"></i>
|
||||||
</div>
|
|
||||||
<div class="hunt"><div class="bar" id="hunt"><span class="t">找找宝宝</span>
|
<div class="hunt"><div class="bar" id="hunt"><span class="t">找找宝宝</span>
|
||||||
<span class="c" data-k="foot"><i></i>小脚丫</span><span class="c" data-k="fist"><i></i>小拳头</span>
|
<span class="c" data-k="foot"><i></i>小脚丫</span><span class="c" data-k="fist"><i></i>小拳头</span>
|
||||||
<span class="c" data-k="knee"><i></i>小膝盖</span><span class="c" data-k="butt"><i></i>小屁股</span></div></div>
|
<span class="c" data-k="knee"><i></i>小膝盖</span><span class="c" data-k="butt"><i></i>小屁股</span></div></div>
|
||||||
<img class="below" src="below.jpg" alt="">
|
|
||||||
</div>
|
</div>
|
||||||
|
<canvas id="cv"></canvas>
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
const W = 375, H = 270, SC = 3; // 头图逻辑尺寸(与首页一致),纹理按 3 倍画
|
const W = 375, H = 270, BH = 2551, HP = H + BH; // 头图 375x270(与首页一致)+ 下面模块 375x2551 = 整页
|
||||||
const REC = /[?&]rec=1/.test(location.search);
|
const REC = /[?&]rec=1/.test(location.search);
|
||||||
const hero = document.getElementById('hero'), cv = document.getElementById('cv');
|
const page = document.querySelector('.page'), cv = document.getElementById('cv');
|
||||||
const hunt = document.getElementById('hunt'), finger = document.getElementById('finger');
|
const hunt = document.getElementById('hunt'), finger = document.getElementById('finger');
|
||||||
const gl = cv.getContext('webgl', { premultipliedAlpha: false, preserveDrawingBuffer: REC, antialias: true });
|
const gl = cv.getContext('webgl', { premultipliedAlpha: false, preserveDrawingBuffer: REC, antialias: true });
|
||||||
if (!gl) { hero.classList.add('nogl'); return; }
|
if (!gl) return;
|
||||||
|
// 整页纹理尽量按 3 倍画,但不超过显卡纹理上限和 canvas 面积上限(iOS 约 1600 万像素)
|
||||||
|
const SC = Math.min(3, gl.getParameter(gl.MAX_TEXTURE_SIZE) / HP, Math.sqrt(16e6 / (W * HP)));
|
||||||
|
|
||||||
const VS = 'attribute vec2 a;varying vec2 v;void main(){v=a*.5+.5;v.y=1.-v.y;gl_Position=vec4(a,0.,1.);}';
|
const VS = 'attribute vec2 a;varying vec2 v;void main(){v=a*.5+.5;v.y=1.-v.y;gl_Position=vec4(a,0.,1.);}';
|
||||||
const FS = `
|
const FS = `
|
||||||
precision highp float;
|
precision highp float;
|
||||||
varying vec2 v;
|
varying vec2 v;
|
||||||
uniform sampler2D T;
|
uniform sampler2D T;
|
||||||
uniform vec2 S; // 逻辑尺寸 375x270
|
uniform vec2 S; // 整页逻辑尺寸 375xHP
|
||||||
|
uniform vec2 O; // 当前这一屏:滚动位置 y、屏幕高度(逻辑 px)
|
||||||
uniform vec4 F; // 鼓起处 x,y,角度,高度(px)
|
uniform vec4 F; // 鼓起处 x,y,角度,高度(px)
|
||||||
uniform vec4 K; // 形状 半径x,半径y,尖度(指数),脚趾显隐(0-1)
|
uniform vec4 K; // 形状 半径x,半径y,尖度(指数),脚趾显隐(0-1)
|
||||||
uniform vec4 G; // 左右脚(±1),脚趾蜷曲(0-1),拉长量,0
|
uniform vec4 G; // 左右脚(±1),脚趾蜷曲(0-1),拉长量,0
|
||||||
@@ -105,10 +106,9 @@ float dentR=33.;
|
|||||||
float dent(vec2 p){vec2 d=p-P.xy;return P.z*exp(-dot(d,d)/(dentR*dentR));}
|
float dent(vec2 p){vec2 d=p-P.xy;return P.z*exp(-dot(d,d)/(dentR*dentR));}
|
||||||
float hgt(vec2 p){return tent(p)+toes(p)*.12+dent(p);}
|
float hgt(vec2 p){return tent(p)+toes(p)*.12+dent(p);}
|
||||||
void main(){
|
void main(){
|
||||||
vec2 p=v*S;
|
vec2 p=vec2(v.x*S.x,O.x+v.y*O.y);
|
||||||
vec3 c0=texture2D(T,v).rgb;
|
if(p.y<0.||p.y>S.y){gl_FragColor=vec4(.973,.953,.937,1.);return;} // iOS 橡皮筋拉出页面外
|
||||||
// 白字也接近页面底色,所以只在下缘弧线那一带(y>185)按颜色判断
|
float m=1.; // 整页都是肚皮
|
||||||
float m=p.y<185.?1.:smoothstep(.03,.12,distance(c0,vec3(.973,.953,.937)));
|
|
||||||
float e=1.2;
|
float e=1.2;
|
||||||
vec2 g=vec2(hgt(p+vec2(e,0.))-hgt(p-vec2(e,0.)),hgt(p+vec2(0.,e))-hgt(p-vec2(0.,e)))/(2.*e)*m;
|
vec2 g=vec2(hgt(p+vec2(e,0.))-hgt(p-vec2(e,0.)),hgt(p+vec2(0.,e))-hgt(p-vec2(0.,e)))/(2.*e)*m;
|
||||||
float h=hgt(p)*m;
|
float h=hgt(p)*m;
|
||||||
@@ -142,20 +142,22 @@ void main(){
|
|||||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
||||||
const al = gl.getAttribLocation(pr, 'a'); gl.enableVertexAttribArray(al); gl.vertexAttribPointer(al, 2, gl.FLOAT, false, 0, 0);
|
const al = gl.getAttribLocation(pr, 'a'); gl.enableVertexAttribArray(al); gl.vertexAttribPointer(al, 2, gl.FLOAT, false, 0, 0);
|
||||||
const U = n => gl.getUniformLocation(pr, n);
|
const U = n => gl.getUniformLocation(pr, n);
|
||||||
const uS = U('S'), uF = U('F'), uK = U('K'), uG = U('G'), uP = U('P'), uJ = U('J'), uT = U('Tm');
|
const uO = U('O'), uS = U('S'), uF = U('F'), uK = U('K'), uG = U('G'), uP = U('P'), uJ = U('J'), uT = U('Tm');
|
||||||
gl.uniform2f(uS, W, H);
|
gl.uniform2f(uS, W, HP);
|
||||||
|
|
||||||
/* ---------- 纹理:canvas 现场合成,宝宝卡的悄悄话会变 ---------- */
|
/* ---------- 纹理:canvas 现场合成,宝宝卡的悄悄话会变 ---------- */
|
||||||
const tc = document.createElement('canvas'); tc.width = W * SC; tc.height = H * SC;
|
const tc = document.createElement('canvas'); tc.width = Math.floor(W * SC); tc.height = Math.floor(HP * SC);
|
||||||
|
const hc = document.createElement('canvas'); hc.width = tc.width; hc.height = Math.ceil(H * SC); // 只换头图那一截时用
|
||||||
const cx = tc.getContext('2d');
|
const cx = tc.getContext('2d');
|
||||||
const SRC = { bg: 'belly_bg.jpg', top: 'top.png', pill: '../_hero/pill.png', week: '../_hero/week.png', prog: '../_hero/prog.png' };
|
const SRC = { bg: 'belly_bg.jpg', top: 'top.png', pill: '../_hero/pill.png', week: '../_hero/week.png', prog: '../_hero/prog.png', below: 'below.jpg' };
|
||||||
const IMG = {}; let loaded = 0;
|
const IMG = {}; let loaded = 0;
|
||||||
const tex = gl.createTexture(); let ready = false;
|
const tex = gl.createTexture(); let ready = false;
|
||||||
const FONT = '-apple-system,"PingFang SC","Noto Sans SC",sans-serif';
|
const FONT = '-apple-system,"PingFang SC","Noto Sans SC",sans-serif';
|
||||||
const card = { line: '我认得妈妈的声音' };
|
const card = { line: '我认得妈妈的声音' };
|
||||||
function rr(x, y, w, h, r) { cx.beginPath(); cx.moveTo(x + r, y); cx.arcTo(x + w, y, x + w, y + h, r); cx.arcTo(x + w, y + h, x, y + h, r); cx.arcTo(x, y + h, x, y, r); cx.arcTo(x, y, x + w, y, r); cx.closePath(); }
|
function rr(x, y, w, h, r) { cx.beginPath(); cx.moveTo(x + r, y); cx.arcTo(x + w, y, x + w, y + h, r); cx.arcTo(x + w, y + h, x, y + h, r); cx.arcTo(x, y + h, x, y, r); cx.arcTo(x, y, x + w, y, r); cx.closePath(); }
|
||||||
function compose() {
|
function compose(full) {
|
||||||
cx.setTransform(SC, 0, 0, SC, 0, 0);
|
cx.setTransform(SC, 0, 0, SC, 0, 0);
|
||||||
|
if (full) cx.drawImage(IMG.below, 0, H, W, BH);
|
||||||
cx.drawImage(IMG.bg, 0, 0, W, H);
|
cx.drawImage(IMG.bg, 0, 0, W, H);
|
||||||
// 右侧原来是宝宝插画的位置:一大团很淡的暖光 + 几颗小光点,让肚皮不空
|
// 右侧原来是宝宝插画的位置:一大团很淡的暖光 + 几颗小光点,让肚皮不空
|
||||||
const gr = cx.createRadialGradient(292, 118, 6, 292, 118, 120);
|
const gr = cx.createRadialGradient(292, 118, 6, 292, 118, 120);
|
||||||
@@ -196,7 +198,10 @@ void main(){
|
|||||||
cx.fillText(ln, X + 26, Y + 101.5);
|
cx.fillText(ln, X + 26, Y + 101.5);
|
||||||
cx.shadowColor = 'transparent';
|
cx.shadowColor = 'transparent';
|
||||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, tc);
|
if (full) { gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, tc); return; }
|
||||||
|
// 悄悄话变了:只把头图那一截重新传上去,整页纹理很大,别每次全传
|
||||||
|
const hx = hc.getContext('2d'); hx.drawImage(tc, 0, 0);
|
||||||
|
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGB, gl.UNSIGNED_BYTE, hc);
|
||||||
}
|
}
|
||||||
function setCard(line) { card.line = line; if (ready) compose(); }
|
function setCard(line) { card.line = line; if (ready) compose(); }
|
||||||
Object.keys(SRC).forEach(k => {
|
Object.keys(SRC).forEach(k => {
|
||||||
@@ -208,16 +213,19 @@ void main(){
|
|||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||||
ready = true; compose();
|
ready = true; compose(true); cv.classList.add('on');
|
||||||
(document.fonts ? document.fonts.ready : Promise.resolve()).then(() => { compose(); window.__ready = true; });
|
(document.fonts ? document.fonts.ready : Promise.resolve()).then(() => { compose(true); window.__ready = true; });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
im.src = SRC[k];
|
im.src = SRC[k];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 页面 px ↔ 逻辑 px;当前这一屏在整页里的位置
|
||||||
|
let K = 1;
|
||||||
|
const view = () => { const r = page.getBoundingClientRect(); K = r.width / W; return { y: -r.top / K, h: cv.clientHeight / K }; };
|
||||||
function resize() {
|
function resize() {
|
||||||
const dpr = Math.min(window.devicePixelRatio || 1, 3), r = hero.getBoundingClientRect();
|
const dpr = Math.min(window.devicePixelRatio || 1, 2); // 整屏都要算,最多 2 倍
|
||||||
cv.width = Math.round(r.width * dpr); cv.height = Math.round(r.height * dpr);
|
cv.width = Math.round(cv.clientWidth * dpr); cv.height = Math.round(cv.clientHeight * dpr);
|
||||||
gl.viewport(0, 0, cv.width, cv.height);
|
gl.viewport(0, 0, cv.width, cv.height);
|
||||||
}
|
}
|
||||||
resize(); addEventListener('resize', resize);
|
resize(); addEventListener('resize', resize);
|
||||||
@@ -243,14 +251,17 @@ void main(){
|
|||||||
|
|
||||||
// 一半以上的概率专挑字和卡片顶(大字「30」、倒计时胶囊、进度条、slogan、宝宝卡),字会被撑起来变形
|
// 一半以上的概率专挑字和卡片顶(大字「30」、倒计时胶囊、进度条、slogan、宝宝卡),字会被撑起来变形
|
||||||
const TEXT_SPOTS = [[62, 120], [100, 74], [104, 124], [96, 166], [230, 26], [292, 104], [300, 80], [150, 168]];
|
const TEXT_SPOTS = [[62, 120], [100, 74], [104, 124], [96, 166], [230, 26], [292, 104], [300, 80], [150, 168]];
|
||||||
|
// 只在当前这一屏里挑位置:头图露着就多半挑头图上的字,滑到下面就在下面的模块上顶
|
||||||
function pickSpot() {
|
function pickSpot() {
|
||||||
|
const vw = view(), y0 = Math.max(vw.y + 60, 20), y1 = Math.min(vw.y + vw.h - 70, HP - 40);
|
||||||
|
const spots = TEXT_SPOTS.filter(s => s[1] > y0 && s[1] < y1);
|
||||||
for (let i = 0; i < 40; i++) {
|
for (let i = 0; i < 40; i++) {
|
||||||
let x, y;
|
let x, y;
|
||||||
if (Math.random() < .7) { const s = TEXT_SPOTS[Math.floor(Math.random() * TEXT_SPOTS.length)]; x = s[0] + (Math.random() - .5) * 16; y = s[1] + (Math.random() - .5) * 10; }
|
if (spots.length && Math.random() < .7) { const s = spots[Math.floor(Math.random() * spots.length)]; x = s[0] + (Math.random() - .5) * 16; y = s[1] + (Math.random() - .5) * 10; }
|
||||||
else { x = 220 + Math.random() * 130; y = 70 + Math.random() * 120; }
|
else { x = 50 + Math.random() * 275; y = y0 + Math.random() * Math.max(y1 - y0, 1); }
|
||||||
if (Math.hypot(x - ft.x, y - ft.y) > 80) return { x, y };
|
if (Math.hypot(x - ft.x, y - ft.y) > 80) return { x, y };
|
||||||
}
|
}
|
||||||
return { x: 300, y: 120 };
|
return { x: 190, y: (y0 + y1) / 2 };
|
||||||
}
|
}
|
||||||
function appear() {
|
function appear() {
|
||||||
const key = ORDER[seq++ % ORDER.length], P = PARTS[key];
|
const key = ORDER[seq++ % ORDER.length], P = PARTS[key];
|
||||||
@@ -295,16 +306,27 @@ void main(){
|
|||||||
jg.y.vel += 150; jg.x.vel += (Math.random() - .5) * 90;
|
jg.y.vel += 150; jg.x.vel += (Math.random() - .5) * 90;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hero.addEventListener('pointerdown', e => {
|
page.addEventListener('pointerdown', e => {
|
||||||
const r = hero.getBoundingClientRect();
|
const r = page.getBoundingClientRect();
|
||||||
hero.setPointerCapture && hero.setPointerCapture(e.pointerId);
|
press((e.clientX - r.left) / r.width * W, (e.clientY - r.top) / r.width * W, true);
|
||||||
press((e.clientX - r.left) / r.width * W, (e.clientY - r.top) / r.height * H, true);
|
|
||||||
});
|
});
|
||||||
const up = () => press(0, 0, false);
|
page.addEventListener('pointerup', () => press(0, 0, false));
|
||||||
hero.addEventListener('pointerup', up); hero.addEventListener('pointercancel', up);
|
// 手指一滑变成滚动:浏览器会发 pointercancel,这时窝悄悄平回去,不弹
|
||||||
|
page.addEventListener('pointercancel', () => { if (pk.held) { pk.held = false; pk.d.to = 0; pk.d.k = 300; pk.d.c = 34; } });
|
||||||
|
|
||||||
|
let lastY = 0, still = 0;
|
||||||
function step(dt) {
|
function step(dt) {
|
||||||
t += dt;
|
t += dt;
|
||||||
|
// 滑动停下来 0.35 秒,看看宝宝在不在这一屏里;不在就让它挪过来,在这一屏里慢慢顶一下
|
||||||
|
const vw = view();
|
||||||
|
if (Math.abs(vw.y - lastY) > 1.5) { still = 0; lastY = vw.y; }
|
||||||
|
else if (still < .35 && (still += dt) >= .35) {
|
||||||
|
const fy = ft.y + ft.oy, seen = fy > vw.y + 30 && fy < vw.y + vw.h - 30;
|
||||||
|
if (!seen) {
|
||||||
|
if (mode === 'show' || mode === 'hide') { ft.h.v = 0; ft.h.vel = 0; mode = 'wait'; wait = .5 + Math.random() * .6; }
|
||||||
|
else if (mode === 'wait') wait = Math.min(wait, .5 + Math.random() * .6);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mode === 'wait') { wait -= dt; if (wait <= 0) appear(); }
|
if (mode === 'wait') { wait -= dt; if (wait <= 0) appear(); }
|
||||||
else if (mode === 'show') {
|
else if (mode === 'show') {
|
||||||
ft.life += dt;
|
ft.life += dt;
|
||||||
@@ -344,6 +366,7 @@ void main(){
|
|||||||
gl.uniform4f(uP, pk.x, pk.y, pk.d.v, 0);
|
gl.uniform4f(uP, pk.x, pk.y, pk.d.v, 0);
|
||||||
gl.uniform2f(uJ, jg.x.v, jg.y.v);
|
gl.uniform2f(uJ, jg.x.v, jg.y.v);
|
||||||
gl.uniform1f(uT, t);
|
gl.uniform1f(uT, t);
|
||||||
|
const vw = view(); gl.uniform2f(uO, vw.y, vw.h);
|
||||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +377,7 @@ void main(){
|
|||||||
window.__tap = (x, y) => press(x, y, true);
|
window.__tap = (x, y) => press(x, y, true);
|
||||||
window.__foot = () => ({ x: ft.x + ft.ox, y: ft.y + ft.oy, h: ft.h.v, mode, key: ft.key });
|
window.__foot = () => ({ x: ft.x + ft.ox, y: ft.y + ft.oy, h: ft.h.v, mode, key: ft.key });
|
||||||
window.__finger = (x, y, on) => {
|
window.__finger = (x, y, on) => {
|
||||||
finger.style.left = x / W * 100 + '%'; finger.style.top = y / H * 100 + '%';
|
finger.style.left = x * K + 'px'; finger.style.top = y * K + 'px';
|
||||||
finger.classList.toggle('on', !!on);
|
finger.classList.toggle('on', !!on);
|
||||||
};
|
};
|
||||||
window.__seed = s => { let z = s; Math.random = () => ((z = (z * 16807) % 2147483647) / 2147483647); };
|
window.__seed = s => { let z = s; Math.random = () => ((z = (z * 16807) % 2147483647) / 2147483647); };
|
||||||
|
|||||||
Reference in New Issue
Block a user