Prevent flying to the same element and reduce chirp volume

This commit is contained in:
Idrees Hassan
2026-03-21 14:11:58 -07:00
parent c1511aae71
commit 61fbe89986
10 changed files with 80 additions and 200 deletions

BIN
dist/extension.zip vendored

Binary file not shown.

View File

@@ -478,7 +478,7 @@
"face": "#39333e", "face": "#39333e",
"wing": "#312c35", "wing": "#312c35",
"wing-edge": "#171617", "wing-edge": "#171617",
"underbelly": "#ff82ba", "underbelly": "#ff7eb8",
"belly": "#ff6eaf", "belly": "#ff6eaf",
"foot": "#2e2c2e", "foot": "#2e2c2e",
"theme-highlight": "#ff82ba" "theme-highlight": "#ff82ba"
@@ -1359,7 +1359,7 @@
3500 + Math.random() * 600 * count, 3500 + Math.random() * 600 * count,
2100 + Math.random() * 200 * count, 2100 + Math.random() * 200 * count,
1600 + Math.random() * 400 * count]; 1600 + Math.random() * 400 * count];
const VOLUMES = [0.0001, 0.2, 0.2, 0.0001]; const VOLUMES = [0.00005, 0.165, 0.165, 0.0001];
const oscillator = this.audioContext.createOscillator(); const oscillator = this.audioContext.createOscillator();
oscillator.type = "sine"; oscillator.type = "sine";
@@ -2425,7 +2425,7 @@
}), }),
new Separator(), new Separator(),
new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }), new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }),
new MenuItem("2026.3.19", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.19"); }, false), new MenuItem("2026.3.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.20"); }, false),
]; ];
/** @type {Birb} */ /** @type {Birb} */
@@ -2615,7 +2615,7 @@
setInterval(update, UPDATE_INTERVAL); setInterval(update, UPDATE_INTERVAL);
focusOnElement(true); flyToElement(true);
// TODO: Remove // TODO: Remove
insertFieldGuide(); insertFieldGuide();
} }
@@ -2636,11 +2636,11 @@
// Idle for a while, do something // Idle for a while, do something
if (focusedElement === null) { if (focusedElement === null) {
// Fly to an element // Fly to an element
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} else if (Math.random() < FOCUS_SWITCH_CHANCE) { } else if (Math.random() < FOCUS_SWITCH_CHANCE) {
// Fly to another element if idle for a longer while // Fly to another element if idle for a longer while
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} }
} }
@@ -2676,7 +2676,7 @@
// Update the bird's position // Update the bird's position
if (currentState === States.IDLE) { if (currentState === States.IDLE) {
if (focusedElement && !isWithinHorizontalBounds()) { if (focusedElement && !isWithinHorizontalBounds()) {
flySomewhere(); flyToElement();
} }
birdY = getFocusedY(); birdY = getFocusedY();
} else if (currentState === States.FLYING) { } else if (currentState === States.FLYING) {
@@ -2692,7 +2692,7 @@
startY += targetY - oldTargetY; startY += targetY - oldTargetY;
if (targetY < 0 || targetY > getWindowHeight()) { if (targetY < 0 || targetY > getWindowHeight()) {
// Fly to another element or the ground if the focused element moves out of bounds // Fly to another element or the ground if the focused element moves out of bounds
flySomewhere(); flyToElement();
} }
if (birb.draw(SPECIES[currentSpecies], currentHat)) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
@@ -3211,26 +3211,6 @@
return getWindowHeight() - focusedBounds.top; return getWindowHeight() - focusedBounds.top;
} }
/**
* Fly to either an element or the ground
*/
function flySomewhere() {
// On mobile, always prefer to focus on an element
// If not mobile, 50% chance to focus on ground
// if ((!isMobile() && coinFlip()) || !focusOnElement()) {
// focusOnGround();
// }
if (!focusOnElement()) {
focusOnGround();
}
}
function focusOnGround() {
focusedElement = null;
updateFocusedElementBounds();
flyTo(Math.random() * window.innerWidth, 0);
}
/** /**
* @returns {HTMLElement|null} The random element, or null if no valid element was found * @returns {HTMLElement|null} The random element, or null if no valid element was found
*/ */
@@ -3262,20 +3242,20 @@
} }
/** /**
* Focus on an element within the viewport * Fly to an element within the viewport
* @param {boolean} [teleport] Whether to teleport to the element instead of flying * @param {boolean} [teleport] Whether to teleport to the element instead of flying
* @returns Whether an element to focus on was found * @returns Whether an element to fly to was found (null if flying to the ground)
*/ */
function focusOnElement(teleport = false) { function flyToElement(teleport = false) {
if (frozen) { if (frozen) {
return false; return false;
} }
const previousElement = focusedElement;
focusedElement = getRandomValidElement(); focusedElement = getRandomValidElement();
log("Focusing on element: ", focusedElement);
updateFocusedElementBounds(); updateFocusedElementBounds();
if (teleport) { if (teleport) {
teleportTo(getFocusedElementRandomX(), getFocusedY()); teleportTo(getFocusedElementRandomX(), getFocusedY());
} else { } else if (focusedElement !== previousElement) {
flyTo(getFocusedElementRandomX(), getFocusedY()); flyTo(getFocusedElementRandomX(), getFocusedY());
} }
return focusedElement !== null; return focusedElement !== null;

View File

@@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "Pocket Bird", "name": "Pocket Bird",
"description": "It's a pet bird in your browser, what more could you want?", "description": "It's a pet bird in your browser, what more could you want?",
"version": "2026.3.19", "version": "2026.3.20",
"homepage_url": "https://idreesinc.com", "homepage_url": "https://idreesinc.com",
"icons": { "icons": {
"48": "images/icons/transparent/48x48x1.png", "48": "images/icons/transparent/48x48x1.png",

48
dist/obsidian/main.js vendored
View File

@@ -1,7 +1,7 @@
const { Plugin, Notice } = require('obsidian'); const { Plugin, Notice } = require('obsidian');
module.exports = class PocketBird extends Plugin { module.exports = class PocketBird extends Plugin {
onload() { onload() {
console.log("Loading Pocket Bird version 2026.3.19..."); console.log("Loading Pocket Bird version 2026.3.20...");
const OBSIDIAN_PLUGIN = this; const OBSIDIAN_PLUGIN = this;
(function () { (function () {
'use strict'; 'use strict';
@@ -483,7 +483,7 @@ module.exports = class PocketBird extends Plugin {
"face": "#39333e", "face": "#39333e",
"wing": "#312c35", "wing": "#312c35",
"wing-edge": "#171617", "wing-edge": "#171617",
"underbelly": "#ff82ba", "underbelly": "#ff7eb8",
"belly": "#ff6eaf", "belly": "#ff6eaf",
"foot": "#2e2c2e", "foot": "#2e2c2e",
"theme-highlight": "#ff82ba" "theme-highlight": "#ff82ba"
@@ -1364,7 +1364,7 @@ module.exports = class PocketBird extends Plugin {
3500 + Math.random() * 600 * count, 3500 + Math.random() * 600 * count,
2100 + Math.random() * 200 * count, 2100 + Math.random() * 200 * count,
1600 + Math.random() * 400 * count]; 1600 + Math.random() * 400 * count];
const VOLUMES = [0.0001, 0.2, 0.2, 0.0001]; const VOLUMES = [0.00005, 0.165, 0.165, 0.0001];
const oscillator = this.audioContext.createOscillator(); const oscillator = this.audioContext.createOscillator();
oscillator.type = "sine"; oscillator.type = "sine";
@@ -2458,7 +2458,7 @@ module.exports = class PocketBird extends Plugin {
}), }),
new Separator(), new Separator(),
new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }), new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }),
new MenuItem("2026.3.19", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.19"); }, false), new MenuItem("2026.3.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.20"); }, false),
]; ];
/** @type {Birb} */ /** @type {Birb} */
@@ -2648,7 +2648,7 @@ module.exports = class PocketBird extends Plugin {
setInterval(update, UPDATE_INTERVAL); setInterval(update, UPDATE_INTERVAL);
focusOnElement(true); flyToElement(true);
// TODO: Remove // TODO: Remove
insertFieldGuide(); insertFieldGuide();
} }
@@ -2669,11 +2669,11 @@ module.exports = class PocketBird extends Plugin {
// Idle for a while, do something // Idle for a while, do something
if (focusedElement === null) { if (focusedElement === null) {
// Fly to an element // Fly to an element
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} else if (Math.random() < FOCUS_SWITCH_CHANCE) { } else if (Math.random() < FOCUS_SWITCH_CHANCE) {
// Fly to another element if idle for a longer while // Fly to another element if idle for a longer while
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} }
} }
@@ -2709,7 +2709,7 @@ module.exports = class PocketBird extends Plugin {
// Update the bird's position // Update the bird's position
if (currentState === States.IDLE) { if (currentState === States.IDLE) {
if (focusedElement && !isWithinHorizontalBounds()) { if (focusedElement && !isWithinHorizontalBounds()) {
flySomewhere(); flyToElement();
} }
birdY = getFocusedY(); birdY = getFocusedY();
} else if (currentState === States.FLYING) { } else if (currentState === States.FLYING) {
@@ -2725,7 +2725,7 @@ module.exports = class PocketBird extends Plugin {
startY += targetY - oldTargetY; startY += targetY - oldTargetY;
if (targetY < 0 || targetY > getWindowHeight()) { if (targetY < 0 || targetY > getWindowHeight()) {
// Fly to another element or the ground if the focused element moves out of bounds // Fly to another element or the ground if the focused element moves out of bounds
flySomewhere(); flyToElement();
} }
if (birb.draw(SPECIES[currentSpecies], currentHat)) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
@@ -3244,26 +3244,6 @@ module.exports = class PocketBird extends Plugin {
return getWindowHeight() - focusedBounds.top; return getWindowHeight() - focusedBounds.top;
} }
/**
* Fly to either an element or the ground
*/
function flySomewhere() {
// On mobile, always prefer to focus on an element
// If not mobile, 50% chance to focus on ground
// if ((!isMobile() && coinFlip()) || !focusOnElement()) {
// focusOnGround();
// }
if (!focusOnElement()) {
focusOnGround();
}
}
function focusOnGround() {
focusedElement = null;
updateFocusedElementBounds();
flyTo(Math.random() * window.innerWidth, 0);
}
/** /**
* @returns {HTMLElement|null} The random element, or null if no valid element was found * @returns {HTMLElement|null} The random element, or null if no valid element was found
*/ */
@@ -3295,20 +3275,20 @@ module.exports = class PocketBird extends Plugin {
} }
/** /**
* Focus on an element within the viewport * Fly to an element within the viewport
* @param {boolean} [teleport] Whether to teleport to the element instead of flying * @param {boolean} [teleport] Whether to teleport to the element instead of flying
* @returns Whether an element to focus on was found * @returns Whether an element to fly to was found (null if flying to the ground)
*/ */
function focusOnElement(teleport = false) { function flyToElement(teleport = false) {
if (frozen) { if (frozen) {
return false; return false;
} }
const previousElement = focusedElement;
focusedElement = getRandomValidElement(); focusedElement = getRandomValidElement();
log("Focusing on element: ", focusedElement);
updateFocusedElementBounds(); updateFocusedElementBounds();
if (teleport) { if (teleport) {
teleportTo(getFocusedElementRandomX(), getFocusedY()); teleportTo(getFocusedElementRandomX(), getFocusedY());
} else { } else if (focusedElement !== previousElement) {
flyTo(getFocusedElementRandomX(), getFocusedY()); flyTo(getFocusedElementRandomX(), getFocusedY());
} }
return focusedElement !== null; return focusedElement !== null;

View File

@@ -1,7 +1,7 @@
{ {
"id": "pocket-bird", "id": "pocket-bird",
"name": "Pocket Bird", "name": "Pocket Bird",
"version": "2026.3.19", "version": "2026.3.20",
"minAppVersion": "0.15.0", "minAppVersion": "0.15.0",
"description": "Add a pet bird to fly around your notes and keep you company!", "description": "Add a pet bird to fly around your notes and keep you company!",
"author": "Idrees Hassan", "author": "Idrees Hassan",

View File

@@ -1,7 +1,7 @@
// ==UserScript== // ==UserScript==
// @name Pocket Bird // @name Pocket Bird
// @namespace https://idreesinc.com // @namespace https://idreesinc.com
// @version 2026.3.19 // @version 2026.3.20
// @description It's a pet bird in your browser, what more could you want? // @description It's a pet bird in your browser, what more could you want?
// @author Idrees // @author Idrees
// @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js // @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
@@ -492,7 +492,7 @@
"face": "#39333e", "face": "#39333e",
"wing": "#312c35", "wing": "#312c35",
"wing-edge": "#171617", "wing-edge": "#171617",
"underbelly": "#ff82ba", "underbelly": "#ff7eb8",
"belly": "#ff6eaf", "belly": "#ff6eaf",
"foot": "#2e2c2e", "foot": "#2e2c2e",
"theme-highlight": "#ff82ba" "theme-highlight": "#ff82ba"
@@ -1373,7 +1373,7 @@
3500 + Math.random() * 600 * count, 3500 + Math.random() * 600 * count,
2100 + Math.random() * 200 * count, 2100 + Math.random() * 200 * count,
1600 + Math.random() * 400 * count]; 1600 + Math.random() * 400 * count];
const VOLUMES = [0.0001, 0.2, 0.2, 0.0001]; const VOLUMES = [0.00005, 0.165, 0.165, 0.0001];
const oscillator = this.audioContext.createOscillator(); const oscillator = this.audioContext.createOscillator();
oscillator.type = "sine"; oscillator.type = "sine";
@@ -2420,7 +2420,7 @@
}), }),
new Separator(), new Separator(),
new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }), new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }),
new MenuItem("2026.3.19", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.19"); }, false), new MenuItem("2026.3.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.20"); }, false),
]; ];
/** @type {Birb} */ /** @type {Birb} */
@@ -2610,7 +2610,7 @@
setInterval(update, UPDATE_INTERVAL); setInterval(update, UPDATE_INTERVAL);
focusOnElement(true); flyToElement(true);
// TODO: Remove // TODO: Remove
insertFieldGuide(); insertFieldGuide();
} }
@@ -2631,11 +2631,11 @@
// Idle for a while, do something // Idle for a while, do something
if (focusedElement === null) { if (focusedElement === null) {
// Fly to an element // Fly to an element
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} else if (Math.random() < FOCUS_SWITCH_CHANCE) { } else if (Math.random() < FOCUS_SWITCH_CHANCE) {
// Fly to another element if idle for a longer while // Fly to another element if idle for a longer while
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} }
} }
@@ -2671,7 +2671,7 @@
// Update the bird's position // Update the bird's position
if (currentState === States.IDLE) { if (currentState === States.IDLE) {
if (focusedElement && !isWithinHorizontalBounds()) { if (focusedElement && !isWithinHorizontalBounds()) {
flySomewhere(); flyToElement();
} }
birdY = getFocusedY(); birdY = getFocusedY();
} else if (currentState === States.FLYING) { } else if (currentState === States.FLYING) {
@@ -2687,7 +2687,7 @@
startY += targetY - oldTargetY; startY += targetY - oldTargetY;
if (targetY < 0 || targetY > getWindowHeight()) { if (targetY < 0 || targetY > getWindowHeight()) {
// Fly to another element or the ground if the focused element moves out of bounds // Fly to another element or the ground if the focused element moves out of bounds
flySomewhere(); flyToElement();
} }
if (birb.draw(SPECIES[currentSpecies], currentHat)) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
@@ -3206,26 +3206,6 @@
return getWindowHeight() - focusedBounds.top; return getWindowHeight() - focusedBounds.top;
} }
/**
* Fly to either an element or the ground
*/
function flySomewhere() {
// On mobile, always prefer to focus on an element
// If not mobile, 50% chance to focus on ground
// if ((!isMobile() && coinFlip()) || !focusOnElement()) {
// focusOnGround();
// }
if (!focusOnElement()) {
focusOnGround();
}
}
function focusOnGround() {
focusedElement = null;
updateFocusedElementBounds();
flyTo(Math.random() * window.innerWidth, 0);
}
/** /**
* @returns {HTMLElement|null} The random element, or null if no valid element was found * @returns {HTMLElement|null} The random element, or null if no valid element was found
*/ */
@@ -3257,20 +3237,20 @@
} }
/** /**
* Focus on an element within the viewport * Fly to an element within the viewport
* @param {boolean} [teleport] Whether to teleport to the element instead of flying * @param {boolean} [teleport] Whether to teleport to the element instead of flying
* @returns Whether an element to focus on was found * @returns Whether an element to fly to was found (null if flying to the ground)
*/ */
function focusOnElement(teleport = false) { function flyToElement(teleport = false) {
if (frozen) { if (frozen) {
return false; return false;
} }
const previousElement = focusedElement;
focusedElement = getRandomValidElement(); focusedElement = getRandomValidElement();
log("Focusing on element: ", focusedElement);
updateFocusedElementBounds(); updateFocusedElementBounds();
if (teleport) { if (teleport) {
teleportTo(getFocusedElementRandomX(), getFocusedY()); teleportTo(getFocusedElementRandomX(), getFocusedY());
} else { } else if (focusedElement !== previousElement) {
flyTo(getFocusedElementRandomX(), getFocusedY()); flyTo(getFocusedElementRandomX(), getFocusedY());
} }
return focusedElement !== null; return focusedElement !== null;

View File

@@ -478,7 +478,7 @@
"face": "#39333e", "face": "#39333e",
"wing": "#312c35", "wing": "#312c35",
"wing-edge": "#171617", "wing-edge": "#171617",
"underbelly": "#ff82ba", "underbelly": "#ff7eb8",
"belly": "#ff6eaf", "belly": "#ff6eaf",
"foot": "#2e2c2e", "foot": "#2e2c2e",
"theme-highlight": "#ff82ba" "theme-highlight": "#ff82ba"
@@ -1359,7 +1359,7 @@
3500 + Math.random() * 600 * count, 3500 + Math.random() * 600 * count,
2100 + Math.random() * 200 * count, 2100 + Math.random() * 200 * count,
1600 + Math.random() * 400 * count]; 1600 + Math.random() * 400 * count];
const VOLUMES = [0.0001, 0.2, 0.2, 0.0001]; const VOLUMES = [0.00005, 0.165, 0.165, 0.0001];
const oscillator = this.audioContext.createOscillator(); const oscillator = this.audioContext.createOscillator();
oscillator.type = "sine"; oscillator.type = "sine";
@@ -2400,7 +2400,7 @@
}), }),
new Separator(), new Separator(),
new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }), new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }),
new MenuItem("2026.3.19", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.19"); }, false), new MenuItem("2026.3.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.20"); }, false),
]; ];
/** @type {Birb} */ /** @type {Birb} */
@@ -2590,7 +2590,7 @@
setInterval(update, UPDATE_INTERVAL); setInterval(update, UPDATE_INTERVAL);
focusOnElement(true); flyToElement(true);
// TODO: Remove // TODO: Remove
insertFieldGuide(); insertFieldGuide();
} }
@@ -2611,11 +2611,11 @@
// Idle for a while, do something // Idle for a while, do something
if (focusedElement === null) { if (focusedElement === null) {
// Fly to an element // Fly to an element
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} else if (Math.random() < FOCUS_SWITCH_CHANCE) { } else if (Math.random() < FOCUS_SWITCH_CHANCE) {
// Fly to another element if idle for a longer while // Fly to another element if idle for a longer while
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} }
} }
@@ -2651,7 +2651,7 @@
// Update the bird's position // Update the bird's position
if (currentState === States.IDLE) { if (currentState === States.IDLE) {
if (focusedElement && !isWithinHorizontalBounds()) { if (focusedElement && !isWithinHorizontalBounds()) {
flySomewhere(); flyToElement();
} }
birdY = getFocusedY(); birdY = getFocusedY();
} else if (currentState === States.FLYING) { } else if (currentState === States.FLYING) {
@@ -2667,7 +2667,7 @@
startY += targetY - oldTargetY; startY += targetY - oldTargetY;
if (targetY < 0 || targetY > getWindowHeight()) { if (targetY < 0 || targetY > getWindowHeight()) {
// Fly to another element or the ground if the focused element moves out of bounds // Fly to another element or the ground if the focused element moves out of bounds
flySomewhere(); flyToElement();
} }
if (birb.draw(SPECIES[currentSpecies], currentHat)) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
@@ -3186,26 +3186,6 @@
return getWindowHeight() - focusedBounds.top; return getWindowHeight() - focusedBounds.top;
} }
/**
* Fly to either an element or the ground
*/
function flySomewhere() {
// On mobile, always prefer to focus on an element
// If not mobile, 50% chance to focus on ground
// if ((!isMobile() && coinFlip()) || !focusOnElement()) {
// focusOnGround();
// }
if (!focusOnElement()) {
focusOnGround();
}
}
function focusOnGround() {
focusedElement = null;
updateFocusedElementBounds();
flyTo(Math.random() * window.innerWidth, 0);
}
/** /**
* @returns {HTMLElement|null} The random element, or null if no valid element was found * @returns {HTMLElement|null} The random element, or null if no valid element was found
*/ */
@@ -3237,20 +3217,20 @@
} }
/** /**
* Focus on an element within the viewport * Fly to an element within the viewport
* @param {boolean} [teleport] Whether to teleport to the element instead of flying * @param {boolean} [teleport] Whether to teleport to the element instead of flying
* @returns Whether an element to focus on was found * @returns Whether an element to fly to was found (null if flying to the ground)
*/ */
function focusOnElement(teleport = false) { function flyToElement(teleport = false) {
if (frozen) { if (frozen) {
return false; return false;
} }
const previousElement = focusedElement;
focusedElement = getRandomValidElement(); focusedElement = getRandomValidElement();
log("Focusing on element: ", focusedElement);
updateFocusedElementBounds(); updateFocusedElementBounds();
if (teleport) { if (teleport) {
teleportTo(getFocusedElementRandomX(), getFocusedY()); teleportTo(getFocusedElementRandomX(), getFocusedY());
} else { } else if (focusedElement !== previousElement) {
flyTo(getFocusedElementRandomX(), getFocusedY()); flyTo(getFocusedElementRandomX(), getFocusedY());
} }
return focusedElement !== null; return focusedElement !== null;

46
dist/web/birb.js vendored
View File

@@ -478,7 +478,7 @@
"face": "#39333e", "face": "#39333e",
"wing": "#312c35", "wing": "#312c35",
"wing-edge": "#171617", "wing-edge": "#171617",
"underbelly": "#ff82ba", "underbelly": "#ff7eb8",
"belly": "#ff6eaf", "belly": "#ff6eaf",
"foot": "#2e2c2e", "foot": "#2e2c2e",
"theme-highlight": "#ff82ba" "theme-highlight": "#ff82ba"
@@ -1359,7 +1359,7 @@
3500 + Math.random() * 600 * count, 3500 + Math.random() * 600 * count,
2100 + Math.random() * 200 * count, 2100 + Math.random() * 200 * count,
1600 + Math.random() * 400 * count]; 1600 + Math.random() * 400 * count];
const VOLUMES = [0.0001, 0.2, 0.2, 0.0001]; const VOLUMES = [0.00005, 0.165, 0.165, 0.0001];
const oscillator = this.audioContext.createOscillator(); const oscillator = this.audioContext.createOscillator();
oscillator.type = "sine"; oscillator.type = "sine";
@@ -2400,7 +2400,7 @@
}), }),
new Separator(), new Separator(),
new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }), new MenuItem(() => `Source Code ${isPetBoostActive() ? " ❤" : ""}`, () => { window.open("https://github.com/IdreesInc/Pocket-Bird"); }),
new MenuItem("2026.3.19", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.19"); }, false), new MenuItem("2026.3.20", () => { alert("Thank you for using Pocket Bird! You are on version: 2026.3.20"); }, false),
]; ];
/** @type {Birb} */ /** @type {Birb} */
@@ -2590,7 +2590,7 @@
setInterval(update, UPDATE_INTERVAL); setInterval(update, UPDATE_INTERVAL);
focusOnElement(true); flyToElement(true);
// TODO: Remove // TODO: Remove
insertFieldGuide(); insertFieldGuide();
} }
@@ -2611,11 +2611,11 @@
// Idle for a while, do something // Idle for a while, do something
if (focusedElement === null) { if (focusedElement === null) {
// Fly to an element // Fly to an element
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} else if (Math.random() < FOCUS_SWITCH_CHANCE) { } else if (Math.random() < FOCUS_SWITCH_CHANCE) {
// Fly to another element if idle for a longer while // Fly to another element if idle for a longer while
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} }
} }
@@ -2651,7 +2651,7 @@
// Update the bird's position // Update the bird's position
if (currentState === States.IDLE) { if (currentState === States.IDLE) {
if (focusedElement && !isWithinHorizontalBounds()) { if (focusedElement && !isWithinHorizontalBounds()) {
flySomewhere(); flyToElement();
} }
birdY = getFocusedY(); birdY = getFocusedY();
} else if (currentState === States.FLYING) { } else if (currentState === States.FLYING) {
@@ -2667,7 +2667,7 @@
startY += targetY - oldTargetY; startY += targetY - oldTargetY;
if (targetY < 0 || targetY > getWindowHeight()) { if (targetY < 0 || targetY > getWindowHeight()) {
// Fly to another element or the ground if the focused element moves out of bounds // Fly to another element or the ground if the focused element moves out of bounds
flySomewhere(); flyToElement();
} }
if (birb.draw(SPECIES[currentSpecies], currentHat)) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
@@ -3186,26 +3186,6 @@
return getWindowHeight() - focusedBounds.top; return getWindowHeight() - focusedBounds.top;
} }
/**
* Fly to either an element or the ground
*/
function flySomewhere() {
// On mobile, always prefer to focus on an element
// If not mobile, 50% chance to focus on ground
// if ((!isMobile() && coinFlip()) || !focusOnElement()) {
// focusOnGround();
// }
if (!focusOnElement()) {
focusOnGround();
}
}
function focusOnGround() {
focusedElement = null;
updateFocusedElementBounds();
flyTo(Math.random() * window.innerWidth, 0);
}
/** /**
* @returns {HTMLElement|null} The random element, or null if no valid element was found * @returns {HTMLElement|null} The random element, or null if no valid element was found
*/ */
@@ -3237,20 +3217,20 @@
} }
/** /**
* Focus on an element within the viewport * Fly to an element within the viewport
* @param {boolean} [teleport] Whether to teleport to the element instead of flying * @param {boolean} [teleport] Whether to teleport to the element instead of flying
* @returns Whether an element to focus on was found * @returns Whether an element to fly to was found (null if flying to the ground)
*/ */
function focusOnElement(teleport = false) { function flyToElement(teleport = false) {
if (frozen) { if (frozen) {
return false; return false;
} }
const previousElement = focusedElement;
focusedElement = getRandomValidElement(); focusedElement = getRandomValidElement();
log("Focusing on element: ", focusedElement);
updateFocusedElementBounds(); updateFocusedElementBounds();
if (teleport) { if (teleport) {
teleportTo(getFocusedElementRandomX(), getFocusedY()); teleportTo(getFocusedElementRandomX(), getFocusedY());
} else { } else if (focusedElement !== previousElement) {
flyTo(getFocusedElementRandomX(), getFocusedY()); flyTo(getFocusedElementRandomX(), getFocusedY());
} }
return focusedElement !== null; return focusedElement !== null;

View File

@@ -406,7 +406,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
setInterval(update, UPDATE_INTERVAL); setInterval(update, UPDATE_INTERVAL);
focusOnElement(true); flyToElement(true);
// TODO: Remove // TODO: Remove
insertFieldGuide(); insertFieldGuide();
} }
@@ -427,11 +427,11 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
// Idle for a while, do something // Idle for a while, do something
if (focusedElement === null) { if (focusedElement === null) {
// Fly to an element // Fly to an element
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} else if (Math.random() < FOCUS_SWITCH_CHANCE) { } else if (Math.random() < FOCUS_SWITCH_CHANCE) {
// Fly to another element if idle for a longer while // Fly to another element if idle for a longer while
focusOnElement(); flyToElement();
lastActionTimestamp = Date.now(); lastActionTimestamp = Date.now();
} }
} }
@@ -467,7 +467,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
// Update the bird's position // Update the bird's position
if (currentState === States.IDLE) { if (currentState === States.IDLE) {
if (focusedElement && !isWithinHorizontalBounds()) { if (focusedElement && !isWithinHorizontalBounds()) {
flySomewhere(); flyToElement();
} }
birdY = getFocusedY(); birdY = getFocusedY();
} else if (currentState === States.FLYING) { } else if (currentState === States.FLYING) {
@@ -483,7 +483,7 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
startY += targetY - oldTargetY; startY += targetY - oldTargetY;
if (targetY < 0 || targetY > getWindowHeight()) { if (targetY < 0 || targetY > getWindowHeight()) {
// Fly to another element or the ground if the focused element moves out of bounds // Fly to another element or the ground if the focused element moves out of bounds
flySomewhere(); flyToElement();
} }
if (birb.draw(SPECIES[currentSpecies], currentHat)) { if (birb.draw(SPECIES[currentSpecies], currentHat)) {
@@ -1006,26 +1006,6 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
return getWindowHeight() - focusedBounds.top; return getWindowHeight() - focusedBounds.top;
} }
/**
* Fly to either an element or the ground
*/
function flySomewhere() {
// On mobile, always prefer to focus on an element
// If not mobile, 50% chance to focus on ground
// if ((!isMobile() && coinFlip()) || !focusOnElement()) {
// focusOnGround();
// }
if (!focusOnElement()) {
focusOnGround();
}
}
function focusOnGround() {
focusedElement = null;
updateFocusedElementBounds();
flyTo(Math.random() * window.innerWidth, 0);
}
/** /**
* @returns {HTMLElement|null} The random element, or null if no valid element was found * @returns {HTMLElement|null} The random element, or null if no valid element was found
*/ */
@@ -1063,20 +1043,20 @@ function startApplication(birbPixels, featherPixels, hatsPixels) {
} }
/** /**
* Focus on an element within the viewport * Fly to an element within the viewport
* @param {boolean} [teleport] Whether to teleport to the element instead of flying * @param {boolean} [teleport] Whether to teleport to the element instead of flying
* @returns Whether an element to focus on was found * @returns Whether an element to fly to was found (null if flying to the ground)
*/ */
function focusOnElement(teleport = false) { function flyToElement(teleport = false) {
if (frozen) { if (frozen) {
return false; return false;
} }
const previousElement = focusedElement;
focusedElement = getRandomValidElement(); focusedElement = getRandomValidElement();
log("Focusing on element: ", focusedElement);
updateFocusedElementBounds(); updateFocusedElementBounds();
if (teleport) { if (teleport) {
teleportTo(getFocusedElementRandomX(), getFocusedY()); teleportTo(getFocusedElementRandomX(), getFocusedY());
} else { } else if (focusedElement !== previousElement) {
flyTo(getFocusedElementRandomX(), getFocusedY()); flyTo(getFocusedElementRandomX(), getFocusedY());
} }
return focusedElement !== null; return focusedElement !== null;

View File

@@ -20,7 +20,7 @@ export class Birdsong {
3500 + Math.random() * 600 * count, 3500 + Math.random() * 600 * count,
2100 + Math.random() * 200 * count, 2100 + Math.random() * 200 * count,
1600 + Math.random() * 400 * count]; 1600 + Math.random() * 400 * count];
const VOLUMES = [0.0001, 0.2, 0.2, 0.0001]; const VOLUMES = [0.00005, 0.165, 0.165, 0.0001];
const oscillator = this.audioContext.createOscillator(); const oscillator = this.audioContext.createOscillator();
oscillator.type = "sine"; oscillator.type = "sine";