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 HOP_DISTANCE = CONFIG.hopDistance;
// 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 MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit";
@@ -957,11 +957,6 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
window.addEventListener("scroll", () => {
lastActionTimestamp = Date.now();
// Can't keep up with scrolling on mobile devices so fly down instead
if (isMobile()) {
// focusOnGround();
}
});
onClick(document, (e) => {
@@ -1668,22 +1663,30 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
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() {
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() {
console.log("Focusing on ground");
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);
}
@@ -1713,7 +1716,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
function updateFocusedElementBounds() {
if (focusedElement === null) {
// 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;
}
const rect = focusedElement.getBoundingClientRect();
@@ -1771,6 +1774,13 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
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
* @param {Anim} animation
@@ -1792,6 +1802,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
if (state === States.IDLE) {
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
*/
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==
// @name Pocket Bird
// @namespace https://idreesinc.com
// @version 2025-10-22-04
// @version 2025-10-23-01
// @description birb
// @author Idrees
// @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 HOP_DISTANCE = CONFIG.hopDistance;
// 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 MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit";
@@ -74,6 +74,10 @@ const STYLESHEET = `:root {
cursor: pointer;
}
.birb-absolute {
position: absolute !important;
}
.birb-decoration {
image-rendering: pixelated;
position: fixed;
@@ -1296,11 +1300,6 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
window.addEventListener("scroll", () => {
lastActionTimestamp = Date.now();
// Can't keep up with scrolling on mobile devices so fly down instead
if (isMobile()) {
// focusOnGround();
}
});
onClick(document, (e) => {
@@ -2007,22 +2006,30 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
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() {
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() {
console.log("Focusing on ground");
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);
}
@@ -2052,7 +2059,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
function updateFocusedElementBounds() {
if (focusedElement === null) {
// 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;
}
const rect = focusedElement.getBoundingClientRect();
@@ -2110,6 +2117,13 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
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
* @param {Anim} animation
@@ -2131,6 +2145,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
if (state === States.IDLE) {
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
*/
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==
// @name Pocket Bird
// @namespace https://idreesinc.com
// @version 2025-10-22-04
// @version 2025-10-23-01
// @description birb
// @author Idrees
// @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 HOP_DISTANCE = CONFIG.hopDistance;
// 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 MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit";
@@ -88,6 +88,10 @@ const STYLESHEET = `:root {
cursor: pointer;
}
.birb-absolute {
position: absolute !important;
}
.birb-decoration {
image-rendering: pixelated;
position: fixed;
@@ -1310,11 +1314,6 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
window.addEventListener("scroll", () => {
lastActionTimestamp = Date.now();
// Can't keep up with scrolling on mobile devices so fly down instead
if (isMobile()) {
// focusOnGround();
}
});
onClick(document, (e) => {
@@ -2021,22 +2020,30 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
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() {
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() {
console.log("Focusing on ground");
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);
}
@@ -2066,7 +2073,7 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
function updateFocusedElementBounds() {
if (focusedElement === null) {
// 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;
}
const rect = focusedElement.getBoundingClientRect();
@@ -2124,6 +2131,13 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
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
* @param {Anim} animation
@@ -2145,6 +2159,12 @@ Promise.all([loadSpriteSheetPixels(SPRITE_SHEET), loadSpriteSheetPixels(DECORATI
if (state === States.IDLE) {
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
*/
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;
}
.birb-absolute {
position: absolute !important;
}
.birb-decoration {
image-rendering: pixelated;
position: fixed;