Switch to absolute positioning when on element

This commit is contained in:
Idrees Hassan
2025-10-23 23:32:01 -04:00
parent 5298b7801b
commit 29f1766a95
5 changed files with 140 additions and 56 deletions

60
birb.js
View File

@@ -32,7 +32,7 @@ const HOP_SPEED = CONFIG.hopSpeed;
const FLY_SPEED = CONFIG.flySpeed; const FLY_SPEED = CONFIG.flySpeed;
const HOP_DISTANCE = CONFIG.hopDistance; const HOP_DISTANCE = CONFIG.hopDistance;
// Time in milliseconds until the user is considered AFK // Time in milliseconds until the user is considered AFK
const AFK_TIME = (debugMode || isMobile()) ? 0 : 1000 * 30; const AFK_TIME = debugMode ? 0 : 1000 * 30;
const SPRITE_HEIGHT = 32; const SPRITE_HEIGHT = 32;
const MENU_ID = "birb-menu"; const MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit"; const MENU_EXIT_ID = "birb-menu-exit";
@@ -957,11 +957,6 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
window.addEventListener("scroll", () => { window.addEventListener("scroll", () => {
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
// Can't keep up with scrolling on mobile devices so fly down instead
if (isMobile()) {
// focusOnGround();
}
}); });
onClick(document, (e) => { onClick(document, (e) => {
@@ -1668,22 +1663,30 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
return birdX >= focusedBounds.left && birdX <= focusedBounds.right; return birdX >= focusedBounds.left && birdX <= focusedBounds.right;
} }
// function getFocusedElementY() {
// if (focusedElement === null) {
// return 0;
// }
// const rect = focusedElement.getBoundingClientRect();
// return window.innerHeight - rect.top;
// }
function getFocusedY() { function getFocusedY() {
return window.innerHeight - focusedBounds.top; return getFullWindowHeight() - focusedBounds.top;
}
/**
* @returns The render-safe height of the inner browser window
*/
function getSafeWindowHeight() {
// Necessary because iOS 26 Safari is terrible and won't render
// fixed elements behind the address bar
return window.innerHeight;
}
/**
* @returns The true height of the inner browser window
*/
function getFullWindowHeight() {
return document.documentElement.clientHeight;
} }
function focusOnGround() { function focusOnGround() {
console.log("Focusing on ground"); console.log("Focusing on ground");
focusedElement = null; focusedElement = null;
focusedBounds = { left: 0, right: window.innerWidth, top: window.innerHeight }; focusedBounds = { left: 0, right: window.innerWidth, top: getSafeWindowHeight() };
flyTo(Math.random() * window.innerWidth, 0); flyTo(Math.random() * window.innerWidth, 0);
} }
@@ -1713,7 +1716,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
function updateFocusedElementBounds() { function updateFocusedElementBounds() {
if (focusedElement === null) { if (focusedElement === null) {
// Update ground location to bottom of window // Update ground location to bottom of window
focusedBounds = { left: 0, right: window.innerWidth, top: window.innerHeight }; focusedBounds = { left: 0, right: window.innerWidth, top: getFullWindowHeight() };
return; return;
} }
const rect = focusedElement.getBoundingClientRect(); const rect = focusedElement.getBoundingClientRect();
@@ -1771,6 +1774,13 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
setAnimation(Animations.FLYING); setAnimation(Animations.FLYING);
} }
/**
* @returns {boolean} Whether the bird should be absolutely positioned
*/
function isAbsolute() {
return focusedElement !== null && (currentState === States.IDLE || currentState === States.HOP);
}
/** /**
* Set the current animation and reset the animation timer * Set the current animation and reset the animation timer
* @param {Anim} animation * @param {Anim} animation
@@ -1792,6 +1802,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
if (state === States.IDLE) { if (state === States.IDLE) {
setAnimation(Animations.BOB); setAnimation(Animations.BOB);
} }
if (isAbsolute()) {
canvas.classList.add("birb-absolute");
} else {
canvas.classList.remove("birb-absolute");
}
setY(birdY);
} }
/** /**
@@ -1806,7 +1822,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
* @param {number} y * @param {number} y
*/ */
function setY(y) { function setY(y) {
canvas.style.bottom = `${y}px`; let bottom;
if (isAbsolute()) {
// Position is absolute, convert from fixed
bottom = y - window.scrollY;
} else {
// Position is fixed
bottom = y;
}
canvas.style.bottom = `${bottom}px`;
} }
}); });

View File

@@ -24,7 +24,7 @@ const userScriptHeader =
`// ==UserScript== `// ==UserScript==
// @name Pocket Bird // @name Pocket Bird
// @namespace https://idreesinc.com // @namespace https://idreesinc.com
// @version 2025-10-22-04 // @version 2025-10-23-01
// @description birb // @description birb
// @author Idrees // @author Idrees
// @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/birb.user.js // @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/birb.user.js

64
dist/birb.js vendored
View File

@@ -32,7 +32,7 @@ const HOP_SPEED = CONFIG.hopSpeed;
const FLY_SPEED = CONFIG.flySpeed; const FLY_SPEED = CONFIG.flySpeed;
const HOP_DISTANCE = CONFIG.hopDistance; const HOP_DISTANCE = CONFIG.hopDistance;
// Time in milliseconds until the user is considered AFK // Time in milliseconds until the user is considered AFK
const AFK_TIME = (debugMode || isMobile()) ? 0 : 1000 * 30; const AFK_TIME = debugMode ? 0 : 1000 * 30;
const SPRITE_HEIGHT = 32; const SPRITE_HEIGHT = 32;
const MENU_ID = "birb-menu"; const MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit"; const MENU_EXIT_ID = "birb-menu-exit";
@@ -74,6 +74,10 @@ const STYLESHEET = `:root {
cursor: pointer; cursor: pointer;
} }
.birb-absolute {
position: absolute !important;
}
.birb-decoration { .birb-decoration {
image-rendering: pixelated; image-rendering: pixelated;
position: fixed; position: fixed;
@@ -1296,11 +1300,6 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
window.addEventListener("scroll", () => { window.addEventListener("scroll", () => {
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
// Can't keep up with scrolling on mobile devices so fly down instead
if (isMobile()) {
// focusOnGround();
}
}); });
onClick(document, (e) => { onClick(document, (e) => {
@@ -2007,22 +2006,30 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
return birdX >= focusedBounds.left && birdX <= focusedBounds.right; return birdX >= focusedBounds.left && birdX <= focusedBounds.right;
} }
// function getFocusedElementY() {
// if (focusedElement === null) {
// return 0;
// }
// const rect = focusedElement.getBoundingClientRect();
// return window.innerHeight - rect.top;
// }
function getFocusedY() { function getFocusedY() {
return window.innerHeight - focusedBounds.top; return getFullWindowHeight() - focusedBounds.top;
}
/**
* @returns The render-safe height of the inner browser window
*/
function getSafeWindowHeight() {
// Necessary because iOS 26 Safari is terrible and won't render
// fixed elements behind the address bar
return window.innerHeight;
}
/**
* @returns The true height of the inner browser window
*/
function getFullWindowHeight() {
return document.documentElement.clientHeight;
} }
function focusOnGround() { function focusOnGround() {
console.log("Focusing on ground"); console.log("Focusing on ground");
focusedElement = null; focusedElement = null;
focusedBounds = { left: 0, right: window.innerWidth, top: window.innerHeight }; focusedBounds = { left: 0, right: window.innerWidth, top: getSafeWindowHeight() };
flyTo(Math.random() * window.innerWidth, 0); flyTo(Math.random() * window.innerWidth, 0);
} }
@@ -2052,7 +2059,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
function updateFocusedElementBounds() { function updateFocusedElementBounds() {
if (focusedElement === null) { if (focusedElement === null) {
// Update ground location to bottom of window // Update ground location to bottom of window
focusedBounds = { left: 0, right: window.innerWidth, top: window.innerHeight }; focusedBounds = { left: 0, right: window.innerWidth, top: getFullWindowHeight() };
return; return;
} }
const rect = focusedElement.getBoundingClientRect(); const rect = focusedElement.getBoundingClientRect();
@@ -2110,6 +2117,13 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
setAnimation(Animations.FLYING); setAnimation(Animations.FLYING);
} }
/**
* @returns {boolean} Whether the bird should be absolutely positioned
*/
function isAbsolute() {
return focusedElement !== null && (currentState === States.IDLE || currentState === States.HOP);
}
/** /**
* Set the current animation and reset the animation timer * Set the current animation and reset the animation timer
* @param {Anim} animation * @param {Anim} animation
@@ -2131,6 +2145,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
if (state === States.IDLE) { if (state === States.IDLE) {
setAnimation(Animations.BOB); setAnimation(Animations.BOB);
} }
if (isAbsolute()) {
canvas.classList.add("birb-absolute");
} else {
canvas.classList.remove("birb-absolute");
}
setY(birdY);
} }
/** /**
@@ -2145,7 +2165,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
* @param {number} y * @param {number} y
*/ */
function setY(y) { function setY(y) {
canvas.style.bottom = `${y}px`; let bottom;
if (isAbsolute()) {
// Position is absolute, convert from fixed
bottom = y - window.scrollY;
} else {
// Position is fixed
bottom = y;
}
canvas.style.bottom = `${bottom}px`;
} }
}); });

66
dist/birb.user.js vendored
View File

@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name Pocket Bird // @name Pocket Bird
// @namespace https://idreesinc.com // @namespace https://idreesinc.com
// @version 2025-10-22-04 // @version 2025-10-23-01
// @description birb // @description birb
// @author Idrees // @author Idrees
// @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/birb.user.js // @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/birb.user.js
@@ -46,7 +46,7 @@ const HOP_SPEED = CONFIG.hopSpeed;
const FLY_SPEED = CONFIG.flySpeed; const FLY_SPEED = CONFIG.flySpeed;
const HOP_DISTANCE = CONFIG.hopDistance; const HOP_DISTANCE = CONFIG.hopDistance;
// Time in milliseconds until the user is considered AFK // Time in milliseconds until the user is considered AFK
const AFK_TIME = (debugMode || isMobile()) ? 0 : 1000 * 30; const AFK_TIME = debugMode ? 0 : 1000 * 30;
const SPRITE_HEIGHT = 32; const SPRITE_HEIGHT = 32;
const MENU_ID = "birb-menu"; const MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit"; const MENU_EXIT_ID = "birb-menu-exit";
@@ -88,6 +88,10 @@ const STYLESHEET = `:root {
cursor: pointer; cursor: pointer;
} }
.birb-absolute {
position: absolute !important;
}
.birb-decoration { .birb-decoration {
image-rendering: pixelated; image-rendering: pixelated;
position: fixed; position: fixed;
@@ -1310,11 +1314,6 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
window.addEventListener("scroll", () => { window.addEventListener("scroll", () => {
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
// Can't keep up with scrolling on mobile devices so fly down instead
if (isMobile()) {
// focusOnGround();
}
}); });
onClick(document, (e) => { onClick(document, (e) => {
@@ -2021,22 +2020,30 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
return birdX >= focusedBounds.left && birdX <= focusedBounds.right; return birdX >= focusedBounds.left && birdX <= focusedBounds.right;
} }
// function getFocusedElementY() {
// if (focusedElement === null) {
// return 0;
// }
// const rect = focusedElement.getBoundingClientRect();
// return window.innerHeight - rect.top;
// }
function getFocusedY() { function getFocusedY() {
return window.innerHeight - focusedBounds.top; return getFullWindowHeight() - focusedBounds.top;
}
/**
* @returns The render-safe height of the inner browser window
*/
function getSafeWindowHeight() {
// Necessary because iOS 26 Safari is terrible and won't render
// fixed elements behind the address bar
return window.innerHeight;
}
/**
* @returns The true height of the inner browser window
*/
function getFullWindowHeight() {
return document.documentElement.clientHeight;
} }
function focusOnGround() { function focusOnGround() {
console.log("Focusing on ground"); console.log("Focusing on ground");
focusedElement = null; focusedElement = null;
focusedBounds = { left: 0, right: window.innerWidth, top: window.innerHeight }; focusedBounds = { left: 0, right: window.innerWidth, top: getSafeWindowHeight() };
flyTo(Math.random() * window.innerWidth, 0); flyTo(Math.random() * window.innerWidth, 0);
} }
@@ -2066,7 +2073,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
function updateFocusedElementBounds() { function updateFocusedElementBounds() {
if (focusedElement === null) { if (focusedElement === null) {
// Update ground location to bottom of window // Update ground location to bottom of window
focusedBounds = { left: 0, right: window.innerWidth, top: window.innerHeight }; focusedBounds = { left: 0, right: window.innerWidth, top: getFullWindowHeight() };
return; return;
} }
const rect = focusedElement.getBoundingClientRect(); const rect = focusedElement.getBoundingClientRect();
@@ -2124,6 +2131,13 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
setAnimation(Animations.FLYING); setAnimation(Animations.FLYING);
} }
/**
* @returns {boolean} Whether the bird should be absolutely positioned
*/
function isAbsolute() {
return focusedElement !== null && (currentState === States.IDLE || currentState === States.HOP);
}
/** /**
* Set the current animation and reset the animation timer * Set the current animation and reset the animation timer
* @param {Anim} animation * @param {Anim} animation
@@ -2145,6 +2159,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
if (state === States.IDLE) { if (state === States.IDLE) {
setAnimation(Animations.BOB); setAnimation(Animations.BOB);
} }
if (isAbsolute()) {
canvas.classList.add("birb-absolute");
} else {
canvas.classList.remove("birb-absolute");
}
setY(birdY);
} }
/** /**
@@ -2159,7 +2179,15 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
* @param {number} y * @param {number} y
*/ */
function setY(y) { function setY(y) {
canvas.style.bottom = `${y}px`; let bottom;
if (isAbsolute()) {
// Position is absolute, convert from fixed
bottom = y - window.scrollY;
} else {
// Position is fixed
bottom = y;
}
canvas.style.bottom = `${bottom}px`;
} }
}); });

View File

@@ -21,6 +21,10 @@
cursor: pointer; cursor: pointer;
} }
.birb-absolute {
position: absolute !important;
}
.birb-decoration { .birb-decoration {
image-rendering: pixelated; image-rendering: pixelated;
position: fixed; position: fixed;