Update build and sticky notes

This commit is contained in:
Idrees Hassan
2025-11-14 16:43:49 -05:00
parent 1175c40fa2
commit db78557088
18 changed files with 280 additions and 204 deletions

View File

@@ -3,10 +3,11 @@
![License](https://img.shields.io/github/license/IdreesInc/Pocket-Bird)
[![Chrome Web Store Version](https://img.shields.io/chrome-web-store/v/lbbdngkbbgaecefacpnhnhleggabghak)](https://chromewebstore.google.com/detail/pocket-bird/lbbdngkbbgaecefacpnhnhleggabghak)
[![Mozilla Add-on Version](https://img.shields.io/amo/v/pocket-bird)](https://addons.mozilla.org/en-US/firefox/addon/pocket-bird/)
[![Discord](https://img.shields.io/discord/1398471368403583120?logo=discord&logoColor=fff&label=discord&color=5865F2)](https://discord.gg/6yxE9prcNc)
![](images/preview.png)
It's a pet bird that hops around your browser, what more could you want?
It's a pet bird that hops around your computer, what more could you want?
### Get it for [Google Chrome](https://chromewebstore.google.com/detail/pocket-bird/lbbdngkbbgaecefacpnhnhleggabghak)
@@ -16,7 +17,7 @@ It's a pet bird that hops around your browser, what more could you want?
## Features
- A cute little pixel art bird hops around your webpages as you browse
- A cute little pixel art bird hops around your apps and websites
- Collect rare falling feathers to unlock over 10+ different species of birds
- Add sticky notes that stay on the page even after you refresh
- And most importantly, you can pet the bird!
@@ -51,7 +52,7 @@ Simply move your cursor back and forth over your bird until a heart appears! You
### How do I collect feathers?
Feathers will occasionally fall from the top of your browser window. Clicking on a feather will add a new species to your field guide, allowing you to change the appearance of your pet!
Feathers will occasionally fall from the top of your window. Clicking on a feather will add a new species to your field guide, allowing you to change the appearance of your pet!
### How do I change my bird's appearance?
@@ -67,7 +68,7 @@ Open the Pocket Bird menu by clicking the bird and select "Settings". From there
### Why does Pocket Bird need permission to read and change my data on websites I visit?
Pocket Bird needs these permissions in order to insert the bird and sticky notes into your webpages. Pocket Bird does not collect any of your data or browsing history and all data is stored locally on your device!
If you are running Pocket bird on a browser, the extension needs these permissions in order to insert the bird and sticky notes into your webpages. Pocket Bird does not collect any of your data or browsing history and all data is stored locally on your device!
## Getting in Touch

View File

@@ -12,8 +12,11 @@ const IMAGES_DIR = "./images";
const FONTS_DIR = "./fonts";
const DIST_DIR = "./dist";
const BROWSER_MANIFEST = "./browser-manifest.json";
const OBSIDIAN_MANIFEST = "./obsidian-manifest.json";
const BROWSER_MANIFEST = "./platform-specific/extension/manifest.json";
const OBSIDIAN_MANIFEST = "./platform-specific/obsidian/manifest.json";
const USERSCRIPT_HEADER = "./platform-specific/userscript/header.txt";
const OBSIDIAN_WRAPPER = "./platform-specific/obsidian/wrapper.js";
const USERSCRIPT_DIR = DIST_DIR + "/userscript";
const EXTENSION_DIR = DIST_DIR + "/extension";
const OBSIDIAN_DIR = DIST_DIR + "/obsidian";
@@ -23,8 +26,12 @@ const APPLICATION_ENTRY = SRC_DIR + "/application.js";
const BUNDLED_OUTPUT = DIST_DIR + "/birb.bundled.js";
const BIRB_OUTPUT = DIST_DIR + "/birb.js";
const MONOCRAFT_URL = "https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf";
const VERSION_KEY = "__VERSION__";
const STYLESHEET_KEY = "___STYLESHEET___";
const MONOCRAFT_SRC_KEY = "__MONOCRAFT_SRC__";
const CODE_KEY = "__CODE__";
const spriteSheets = [
{
@@ -66,6 +73,10 @@ const version = `${versionDate}.${buildNumber}`;
buildCache.version = version;
writeFileSync(BUILD_CACHE_PATH, JSON.stringify(buildCache), 'utf8');
// =============================================
// Build JavaScript function
// =============================================
// Bundle with rollup
const bundle = await rollup({
input: APPLICATION_ENTRY,
@@ -94,33 +105,27 @@ for (const spriteSheet of spriteSheets) {
// Insert stylesheet
const stylesheetContent = readFileSync(STYLESHEET_PATH, 'utf8');
birbJs = birbJs.replace(STYLESHEET_KEY, stylesheetContent);
birbJs = birbJs.replace(STYLESHEET_KEY, stylesheetContent).replace(MONOCRAFT_SRC_KEY, MONOCRAFT_URL);
// Build standard javascript file
// Write bundled JavaScript function
writeFileSync(BIRB_OUTPUT, birbJs);
// =============================================
// Build userscript
const userScriptHeader =
`// ==UserScript==
// @name Pocket Bird
// @namespace https://idreesinc.com
// @version ${version}
// @description It's a bird that hops around your web browser, the future is here
// @author Idrees
// @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
// @updateURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// ==/UserScript==
// =============================================
// Get userscript header
const userScriptHeader = readFileSync(USERSCRIPT_HEADER, 'utf8').replaceAll(VERSION_KEY, version);
`;
mkdirSync(USERSCRIPT_DIR, { recursive: true });
const userScript = userScriptHeader + birbJs;
const userScript = userScriptHeader + "\n" + birbJs;
writeFileSync(USERSCRIPT_DIR + '/birb.user.js', userScript);
// =============================================
// Build browser extension
// =============================================
mkdirSync(EXTENSION_DIR, { recursive: true });
// Copy birb.js
@@ -155,26 +160,19 @@ archive.pipe(output);
archive.directory(EXTENSION_DIR + '/', false);
archive.finalize();
// =============================================
// Build Obsidian plugin
// =============================================
mkdirSync(OBSIDIAN_DIR, { recursive: true });
// Wrap birb.js with plugin boilerplate
const obsidianPlugin = `
const { Plugin, Notice } = require('obsidian');
module.exports = class PocketBird extends Plugin {
onload() {
console.log("Loading Pocket Bird version ${version}...");
const OBSIDIAN_PLUGIN = this;
${birbJs}
console.log("Pocket Bird loaded!");
}
let obsidianPlugin = readFileSync(OBSIDIAN_WRAPPER, 'utf8').replace(VERSION_KEY, version).replace(CODE_KEY, birbJs);
onunload() {
// Remove the birb when the plugin is unloaded
document.getElementById('birb')?.remove();
console.log('Pocket Bird unloaded!');
}
};`
// Encode font to data URI since Obsidian plugins can't have external font files
const monocraftFontData = readFileSync(FONTS_DIR + '/Monocraft.otf', 'base64');
const monocraftDataUri = `data:font/otf;base64,${monocraftFontData}`;
obsidianPlugin = obsidianPlugin.replace(MONOCRAFT_URL, monocraftDataUri);
// Create main.js with plugin code
writeFileSync(OBSIDIAN_DIR + '/main.js', obsidianPlugin);

74
dist/birb.js vendored
View File

@@ -99,6 +99,7 @@
offsetX = touch.clientX - elementToMove.offsetLeft;
offsetY = touch.clientY - elementToMove.offsetTop;
e.preventDefault();
e.stopPropagation();
});
document.addEventListener("mouseup", (e) => {
@@ -139,8 +140,9 @@
/**
* @param {() => void} func
* @param {Element} [closeButton]
* @param {boolean} [allowEscape] Whether to allow closing with the Escape key
*/
function makeClosable(func, closeButton) {
function makeClosable(func, closeButton, allowEscape = true) {
if (closeButton) {
onClick(closeButton, func);
}
@@ -148,7 +150,7 @@
if (closeButton && !document.body.contains(closeButton)) {
return;
}
if (e.key === "Escape") {
if (allowEscape && e.key === "Escape") {
func();
}
});
@@ -1230,6 +1232,9 @@
function renderStickyNote(stickyNote, page, onSave, onDelete) {
const noteElement = makeElement("birb-window");
noteElement.classList.add("birb-sticky-note");
const color = getColor(stickyNote.id);
noteElement.style.setProperty("--birb-highlight", color);
noteElement.style.setProperty("--birb-border-color", color);
// Create header
const header = makeElement("birb-window-header");
@@ -1266,7 +1271,7 @@
onDelete();
noteElement.remove();
}
}, closeButton);
}, closeButton, false);
}
if (textarea && textarea instanceof HTMLTextAreaElement) {
@@ -1334,6 +1339,17 @@
onSave();
}
/**
* Get a color based on the mod of the sticky note ID
* @param {string} id
* @returns {string} A color hex code
*/
function getColor(id) {
const colors = ["#ff8baa", "#79bcff", "#d18bff", "#6de192", "#ffd17c", "#ffb37c", "#ff7c7c"];
const index = parseInt(id, 10) % colors.length;
return colors[index];
}
const MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit";
@@ -1508,7 +1524,14 @@
const WINDOW_PIXEL_SIZE = CANVAS_PIXEL_SIZE * BIRB_CSS_SCALE;
// Build-time assets
const STYLESHEET = `:root {
const STYLESHEET = `@font-face {
font-family: 'Monocraft';
src: url("https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf") format('opentype');
font-weight: normal;
font-style: normal;
}
:root {
--birb-border-size: 2px;
--birb-neg-border-size: calc(var(--birb-border-size) * -1);
--birb-double-border-size: calc(var(--birb-border-size) * 2);
@@ -1828,6 +1851,17 @@
.birb-sticky-note {
position: absolute;
box-sizing: border-box;
animation: fade-in 0.15s ease-in;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.birb-sticky-note > .birb-window-content {
@@ -1850,7 +1884,8 @@
}
.birb-sticky-note-input:focus {
outline: none;
outline: none !important;
box-shadow: none !important;
}`;
const SPRITE_SHEET = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAAgCAYAAABjE6FEAAAAAXNSR0IArs4c6QAABD5JREFUeJztnTFrFEEYht9JLAJidwju2YpdBAvzAyIWaXJXpRS0MBCwEBTJDwghhaAgGLTSyupMY2UqG9PYWQRb7yJyYJEIacxnkZ11bm5n9+7Y3Zm9ex8Imezd7Te7O9+zM7N7G4AQQgghhBBCCJkJlO8KkPAREXG9ppRiGyK1hY23BvgUkI7dbjYBAJ1ud6BcRR0IITOKxLSiSFpRNFTOkmNR8VtRJF8WF0U2NobKZccnpEzmfFeA5NNuNvG00UCn3R4qV8nB58942mgkZULqDgVYI3wJqNPtYrvfH1i23e8nQ2BCCCkFcwj8ZXEx+alqCJxWhypjE0ICQFKoOrZPAZl1oPwImTFE5Hzy3/hddXzfAvIhf0LK5ILvCtSNgxs3vMRVSikREZ+3nvB2F0JmFN3z0b0/9oKqx9cUBJleeEYfAzPp2BuqFr3v9W4XkcqPgS1dtoEZIe0CAM/AxAOy220JAG/zn3HsoNs/83R0cu8DNM+85g9yvqJVJBQwAYDdbksXvcx/KqWSOoTW+7Pzwkee1pHMiyDmzjQaH/QyETHfU0qDsIc+xnKIiITWEEl5PGh+8HqsfQp4FMxUWNvpJcvoPzdOAZriOVy7DzwCdm6/SV7f7bYH5mPKkFEIAiZE41vAGYhSKpHetHNlXsnRXynkWDhXIiIydzEaWHbveQ8f1+ew8uoMAHDy+wgA8P5JNHCWKUJGQwLGoIBvrbTxoPlBv7ewuITUDHGJ7/uPY3x9cd3LBaOyuDKvZOXVGT6uz6EICWYKELGA7r9O70JrASKWIAwZpQYb4yD4FjAJm7Wdnrx/Es36cc6VX6jD9VBwDoH1jbeu1035wZpzSGOSYfLZn96QgLX87Nj2cNy1TaPGJuFwurcsC6v7SpcBYGHVr/x8C3htp+d1Ys8VP+4I1SbPMisaCwune8vY+PUJAPDy8m0AwN3DdyMF+P7jGAAm6orr+Gk9UFvAGt0TTVkXQAnWlv/i26/8+KULuPp6mLgEZOZbySJy9j7rJMGRBWizsLqPmw8Pce3qpdTPWgdiIgH5FjAhmlDEpzndWxYzB+x8q0BA4sr/mRAgDAmmYYsPE/S+fAuYkJDpby3JxoUOMDjyqap9OwWIGkkwV4CI5/VsCZ18OwEANDYPXJ/9H2RC6fgWMCGh099aShr4nZ9vgfO2712C5oXJkPMut2JpEtLyS6OxeVDYhvsWMCEkF9GdEFuEWoIh599Ij8OKNwL9raXM9xUpP2RciTYFbNep6DoQQjJRX19cP084hwhDJleAWkJ5EixTPDo2UoRXVR0IIU4UzofeAyKcKsynYXSePU6eiqHLZT6gwPqid2r8sutACMnHfmJO6Pk41n+FU0qh8+xx8rdZRom9Lr3erPjs+RESBvGXEYAa5ONYj8Q3h6J2uQry4oe+swmZduqWg2Pfl+dcUQUb7js+IWS6+Ac8zd6eLzTjoQAAAABJRU5ErkJggg==";
const FEATHER_SPRITE_SHEET = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAARhJREFUWIXtlbENwjAQRf8hSiZIRQ+9WQNRUFIAKzACBSsAA1Ag1mAABqCCBomG3hQQ9OMEx4ZDNH5SikSJ3/fZ5wCJRCKRSPwZ0RzMWmtLAhGvQyUAi9mXP/aFaGjJRQQiguHihMvcFMJUVUYlAMuHixPGy4en1WmVQqgHYHkuZjiEj6a2/LjtYzTY0eiZbgC37Mxh1UN3sn/dr6cCz/LHB/DJj9s+2oMdbtdz6TtfFwQHcMvOInfmQNjsgchNWLXmdfK6gyioAu/6uKrsm1kWLAciKuCuey5nYuXAh234bdmZ6INIUw4E/Ix49xtjCmXfzLL8nY/ktdgnAKwxxgIoXIyqmAOwvIqfiN0ALNd21HYBO9XXGMAdnZTYyHWzWjQAAAAASUVORK5CYII=";
@@ -1871,7 +1906,7 @@
const AFK_TIME = isDebug() ? 0 : 1000 * 5;
const PET_BOOST_DURATION = 1000 * 60 * 5;
const PET_MENU_COOLDOWN = 1000;
const URL_CHECK_INTERVAL = 250;
const URL_CHECK_INTERVAL = 150;
const HOP_DELAY = 500;
// Random event chances per tick
@@ -2011,7 +2046,7 @@
insertModal(`${birdBirb()} Mode`, message);
}),
new Separator(),
new MenuItem("2025.11.14.47", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.14.47"); }, false),
new MenuItem("2025.11.14.205", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.14.205"); }, false),
];
const styleElement = document.createElement("style");
@@ -2128,31 +2163,6 @@
return;
}
// Preload font
const MONOCRAFT_SRC = "https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf";
const fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = `url(${MONOCRAFT_SRC}) format('opentype')`;
document.head.appendChild(fontLink);
// Add stylesheet font-face
const fontFace = `
@font-face {
font-family: 'Monocraft';
src: url(${MONOCRAFT_SRC}) format('opentype');
font-weight: normal;
font-style: normal;
}
`;
try {
const fontStyle = document.createElement("style");
fontStyle.textContent = fontFace;
document.head.appendChild(fontStyle);
} catch (e) {
error("Failed to load font: " + e);
}
load().then(onLoad);
}

BIN
dist/extension.zip vendored

Binary file not shown.

View File

@@ -99,6 +99,7 @@
offsetX = touch.clientX - elementToMove.offsetLeft;
offsetY = touch.clientY - elementToMove.offsetTop;
e.preventDefault();
e.stopPropagation();
});
document.addEventListener("mouseup", (e) => {
@@ -139,8 +140,9 @@
/**
* @param {() => void} func
* @param {Element} [closeButton]
* @param {boolean} [allowEscape] Whether to allow closing with the Escape key
*/
function makeClosable(func, closeButton) {
function makeClosable(func, closeButton, allowEscape = true) {
if (closeButton) {
onClick(closeButton, func);
}
@@ -148,7 +150,7 @@
if (closeButton && !document.body.contains(closeButton)) {
return;
}
if (e.key === "Escape") {
if (allowEscape && e.key === "Escape") {
func();
}
});
@@ -1230,6 +1232,9 @@
function renderStickyNote(stickyNote, page, onSave, onDelete) {
const noteElement = makeElement("birb-window");
noteElement.classList.add("birb-sticky-note");
const color = getColor(stickyNote.id);
noteElement.style.setProperty("--birb-highlight", color);
noteElement.style.setProperty("--birb-border-color", color);
// Create header
const header = makeElement("birb-window-header");
@@ -1266,7 +1271,7 @@
onDelete();
noteElement.remove();
}
}, closeButton);
}, closeButton, false);
}
if (textarea && textarea instanceof HTMLTextAreaElement) {
@@ -1334,6 +1339,17 @@
onSave();
}
/**
* Get a color based on the mod of the sticky note ID
* @param {string} id
* @returns {string} A color hex code
*/
function getColor(id) {
const colors = ["#ff8baa", "#79bcff", "#d18bff", "#6de192", "#ffd17c", "#ffb37c", "#ff7c7c"];
const index = parseInt(id, 10) % colors.length;
return colors[index];
}
const MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit";
@@ -1508,7 +1524,14 @@
const WINDOW_PIXEL_SIZE = CANVAS_PIXEL_SIZE * BIRB_CSS_SCALE;
// Build-time assets
const STYLESHEET = `:root {
const STYLESHEET = `@font-face {
font-family: 'Monocraft';
src: url("https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf") format('opentype');
font-weight: normal;
font-style: normal;
}
:root {
--birb-border-size: 2px;
--birb-neg-border-size: calc(var(--birb-border-size) * -1);
--birb-double-border-size: calc(var(--birb-border-size) * 2);
@@ -1828,6 +1851,17 @@
.birb-sticky-note {
position: absolute;
box-sizing: border-box;
animation: fade-in 0.15s ease-in;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.birb-sticky-note > .birb-window-content {
@@ -1850,7 +1884,8 @@
}
.birb-sticky-note-input:focus {
outline: none;
outline: none !important;
box-shadow: none !important;
}`;
const SPRITE_SHEET = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAAgCAYAAABjE6FEAAAAAXNSR0IArs4c6QAABD5JREFUeJztnTFrFEEYht9JLAJidwju2YpdBAvzAyIWaXJXpRS0MBCwEBTJDwghhaAgGLTSyupMY2UqG9PYWQRb7yJyYJEIacxnkZ11bm5n9+7Y3Zm9ex8Imezd7Te7O9+zM7N7G4AQQgghhBBCCJkJlO8KkPAREXG9ppRiGyK1hY23BvgUkI7dbjYBAJ1ud6BcRR0IITOKxLSiSFpRNFTOkmNR8VtRJF8WF0U2NobKZccnpEzmfFeA5NNuNvG00UCn3R4qV8nB58942mgkZULqDgVYI3wJqNPtYrvfH1i23e8nQ2BCCCkFcwj8ZXEx+alqCJxWhypjE0ICQFKoOrZPAZl1oPwImTFE5Hzy3/hddXzfAvIhf0LK5ILvCtSNgxs3vMRVSikREZ+3nvB2F0JmFN3z0b0/9oKqx9cUBJleeEYfAzPp2BuqFr3v9W4XkcqPgS1dtoEZIe0CAM/AxAOy220JAG/zn3HsoNs/83R0cu8DNM+85g9yvqJVJBQwAYDdbksXvcx/KqWSOoTW+7Pzwkee1pHMiyDmzjQaH/QyETHfU0qDsIc+xnKIiITWEEl5PGh+8HqsfQp4FMxUWNvpJcvoPzdOAZriOVy7DzwCdm6/SV7f7bYH5mPKkFEIAiZE41vAGYhSKpHetHNlXsnRXynkWDhXIiIydzEaWHbveQ8f1+ew8uoMAHDy+wgA8P5JNHCWKUJGQwLGoIBvrbTxoPlBv7ewuITUDHGJ7/uPY3x9cd3LBaOyuDKvZOXVGT6uz6EICWYKELGA7r9O70JrASKWIAwZpQYb4yD4FjAJm7Wdnrx/Es36cc6VX6jD9VBwDoH1jbeu1035wZpzSGOSYfLZn96QgLX87Nj2cNy1TaPGJuFwurcsC6v7SpcBYGHVr/x8C3htp+d1Ys8VP+4I1SbPMisaCwune8vY+PUJAPDy8m0AwN3DdyMF+P7jGAAm6orr+Gk9UFvAGt0TTVkXQAnWlv/i26/8+KULuPp6mLgEZOZbySJy9j7rJMGRBWizsLqPmw8Pce3qpdTPWgdiIgH5FjAhmlDEpzndWxYzB+x8q0BA4sr/mRAgDAmmYYsPE/S+fAuYkJDpby3JxoUOMDjyqap9OwWIGkkwV4CI5/VsCZ18OwEANDYPXJ/9H2RC6fgWMCGh099aShr4nZ9vgfO2712C5oXJkPMut2JpEtLyS6OxeVDYhvsWMCEkF9GdEFuEWoIh599Ij8OKNwL9raXM9xUpP2RciTYFbNep6DoQQjJRX19cP084hwhDJleAWkJ5EixTPDo2UoRXVR0IIU4UzofeAyKcKsynYXSePU6eiqHLZT6gwPqid2r8sutACMnHfmJO6Pk41n+FU0qh8+xx8rdZRom9Lr3erPjs+RESBvGXEYAa5ONYj8Q3h6J2uQry4oe+swmZduqWg2Pfl+dcUQUb7js+IWS6+Ac8zd6eLzTjoQAAAABJRU5ErkJggg==";
const FEATHER_SPRITE_SHEET = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAARhJREFUWIXtlbENwjAQRf8hSiZIRQ+9WQNRUFIAKzACBSsAA1Ag1mAABqCCBomG3hQQ9OMEx4ZDNH5SikSJ3/fZ5wCJRCKRSPwZ0RzMWmtLAhGvQyUAi9mXP/aFaGjJRQQiguHihMvcFMJUVUYlAMuHixPGy4en1WmVQqgHYHkuZjiEj6a2/LjtYzTY0eiZbgC37Mxh1UN3sn/dr6cCz/LHB/DJj9s+2oMdbtdz6TtfFwQHcMvOInfmQNjsgchNWLXmdfK6gyioAu/6uKrsm1kWLAciKuCuey5nYuXAh234bdmZ6INIUw4E/Ix49xtjCmXfzLL8nY/ktdgnAKwxxgIoXIyqmAOwvIqfiN0ALNd21HYBO9XXGMAdnZTYyHWzWjQAAAAASUVORK5CYII=";
@@ -1871,7 +1906,7 @@
const AFK_TIME = isDebug() ? 0 : 1000 * 5;
const PET_BOOST_DURATION = 1000 * 60 * 5;
const PET_MENU_COOLDOWN = 1000;
const URL_CHECK_INTERVAL = 250;
const URL_CHECK_INTERVAL = 150;
const HOP_DELAY = 500;
// Random event chances per tick
@@ -2011,7 +2046,7 @@
insertModal(`${birdBirb()} Mode`, message);
}),
new Separator(),
new MenuItem("2025.11.14.47", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.14.47"); }, false),
new MenuItem("2025.11.14.205", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.14.205"); }, false),
];
const styleElement = document.createElement("style");
@@ -2128,31 +2163,6 @@
return;
}
// Preload font
const MONOCRAFT_SRC = "https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf";
const fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = `url(${MONOCRAFT_SRC}) format('opentype')`;
document.head.appendChild(fontLink);
// Add stylesheet font-face
const fontFace = `
@font-face {
font-family: 'Monocraft';
src: url(${MONOCRAFT_SRC}) format('opentype');
font-weight: normal;
font-style: normal;
}
`;
try {
const fontStyle = document.createElement("style");
fontStyle.textContent = fontFace;
document.head.appendChild(fontStyle);
} catch (e) {
error("Failed to load font: " + e);
}
load().then(onLoad);
}

View File

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

77
dist/obsidian/main.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
{
"id": "pocket-bird",
"name": "Pocket Bird",
"version": "2025.11.14.47",
"version": "2025.11.14.205",
"minAppVersion": "0.15.0",
"description": "It's a pet bird in your Obsidian, what more could you want?",
"author": "Idrees Hassan",

View File

@@ -1,8 +1,8 @@
// ==UserScript==
// @name Pocket Bird
// @namespace https://idreesinc.com
// @version 2025.11.14.47
// @description It's a bird that hops around your web browser, the future is here
// @version 2025.11.14.205
// @description It's a pet bird in your browser, what more could you want?
// @author Idrees
// @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
// @updateURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
@@ -113,6 +113,7 @@
offsetX = touch.clientX - elementToMove.offsetLeft;
offsetY = touch.clientY - elementToMove.offsetTop;
e.preventDefault();
e.stopPropagation();
});
document.addEventListener("mouseup", (e) => {
@@ -153,8 +154,9 @@
/**
* @param {() => void} func
* @param {Element} [closeButton]
* @param {boolean} [allowEscape] Whether to allow closing with the Escape key
*/
function makeClosable(func, closeButton) {
function makeClosable(func, closeButton, allowEscape = true) {
if (closeButton) {
onClick(closeButton, func);
}
@@ -162,7 +164,7 @@
if (closeButton && !document.body.contains(closeButton)) {
return;
}
if (e.key === "Escape") {
if (allowEscape && e.key === "Escape") {
func();
}
});
@@ -1244,6 +1246,9 @@
function renderStickyNote(stickyNote, page, onSave, onDelete) {
const noteElement = makeElement("birb-window");
noteElement.classList.add("birb-sticky-note");
const color = getColor(stickyNote.id);
noteElement.style.setProperty("--birb-highlight", color);
noteElement.style.setProperty("--birb-border-color", color);
// Create header
const header = makeElement("birb-window-header");
@@ -1280,7 +1285,7 @@
onDelete();
noteElement.remove();
}
}, closeButton);
}, closeButton, false);
}
if (textarea && textarea instanceof HTMLTextAreaElement) {
@@ -1348,6 +1353,17 @@
onSave();
}
/**
* Get a color based on the mod of the sticky note ID
* @param {string} id
* @returns {string} A color hex code
*/
function getColor(id) {
const colors = ["#ff8baa", "#79bcff", "#d18bff", "#6de192", "#ffd17c", "#ffb37c", "#ff7c7c"];
const index = parseInt(id, 10) % colors.length;
return colors[index];
}
const MENU_ID = "birb-menu";
const MENU_EXIT_ID = "birb-menu-exit";
@@ -1522,7 +1538,14 @@
const WINDOW_PIXEL_SIZE = CANVAS_PIXEL_SIZE * BIRB_CSS_SCALE;
// Build-time assets
const STYLESHEET = `:root {
const STYLESHEET = `@font-face {
font-family: 'Monocraft';
src: url("https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf") format('opentype');
font-weight: normal;
font-style: normal;
}
:root {
--birb-border-size: 2px;
--birb-neg-border-size: calc(var(--birb-border-size) * -1);
--birb-double-border-size: calc(var(--birb-border-size) * 2);
@@ -1842,6 +1865,17 @@
.birb-sticky-note {
position: absolute;
box-sizing: border-box;
animation: fade-in 0.15s ease-in;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.birb-sticky-note > .birb-window-content {
@@ -1864,7 +1898,8 @@
}
.birb-sticky-note-input:focus {
outline: none;
outline: none !important;
box-shadow: none !important;
}`;
const SPRITE_SHEET = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAAgCAYAAABjE6FEAAAAAXNSR0IArs4c6QAABD5JREFUeJztnTFrFEEYht9JLAJidwju2YpdBAvzAyIWaXJXpRS0MBCwEBTJDwghhaAgGLTSyupMY2UqG9PYWQRb7yJyYJEIacxnkZ11bm5n9+7Y3Zm9ex8Imezd7Te7O9+zM7N7G4AQQgghhBBCCJkJlO8KkPAREXG9ppRiGyK1hY23BvgUkI7dbjYBAJ1ud6BcRR0IITOKxLSiSFpRNFTOkmNR8VtRJF8WF0U2NobKZccnpEzmfFeA5NNuNvG00UCn3R4qV8nB58942mgkZULqDgVYI3wJqNPtYrvfH1i23e8nQ2BCCCkFcwj8ZXEx+alqCJxWhypjE0ICQFKoOrZPAZl1oPwImTFE5Hzy3/hddXzfAvIhf0LK5ILvCtSNgxs3vMRVSikREZ+3nvB2F0JmFN3z0b0/9oKqx9cUBJleeEYfAzPp2BuqFr3v9W4XkcqPgS1dtoEZIe0CAM/AxAOy220JAG/zn3HsoNs/83R0cu8DNM+85g9yvqJVJBQwAYDdbksXvcx/KqWSOoTW+7Pzwkee1pHMiyDmzjQaH/QyETHfU0qDsIc+xnKIiITWEEl5PGh+8HqsfQp4FMxUWNvpJcvoPzdOAZriOVy7DzwCdm6/SV7f7bYH5mPKkFEIAiZE41vAGYhSKpHetHNlXsnRXynkWDhXIiIydzEaWHbveQ8f1+ew8uoMAHDy+wgA8P5JNHCWKUJGQwLGoIBvrbTxoPlBv7ewuITUDHGJ7/uPY3x9cd3LBaOyuDKvZOXVGT6uz6EICWYKELGA7r9O70JrASKWIAwZpQYb4yD4FjAJm7Wdnrx/Es36cc6VX6jD9VBwDoH1jbeu1035wZpzSGOSYfLZn96QgLX87Nj2cNy1TaPGJuFwurcsC6v7SpcBYGHVr/x8C3htp+d1Ys8VP+4I1SbPMisaCwune8vY+PUJAPDy8m0AwN3DdyMF+P7jGAAm6orr+Gk9UFvAGt0TTVkXQAnWlv/i26/8+KULuPp6mLgEZOZbySJy9j7rJMGRBWizsLqPmw8Pce3qpdTPWgdiIgH5FjAhmlDEpzndWxYzB+x8q0BA4sr/mRAgDAmmYYsPE/S+fAuYkJDpby3JxoUOMDjyqap9OwWIGkkwV4CI5/VsCZ18OwEANDYPXJ/9H2RC6fgWMCGh099aShr4nZ9vgfO2712C5oXJkPMut2JpEtLyS6OxeVDYhvsWMCEkF9GdEFuEWoIh599Ij8OKNwL9raXM9xUpP2RciTYFbNep6DoQQjJRX19cP084hwhDJleAWkJ5EixTPDo2UoRXVR0IIU4UzofeAyKcKsynYXSePU6eiqHLZT6gwPqid2r8sutACMnHfmJO6Pk41n+FU0qh8+xx8rdZRom9Lr3erPjs+RESBvGXEYAa5ONYj8Q3h6J2uQry4oe+swmZduqWg2Pfl+dcUQUb7js+IWS6+Ac8zd6eLzTjoQAAAABJRU5ErkJggg==";
const FEATHER_SPRITE_SHEET = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAARhJREFUWIXtlbENwjAQRf8hSiZIRQ+9WQNRUFIAKzACBSsAA1Ag1mAABqCCBomG3hQQ9OMEx4ZDNH5SikSJ3/fZ5wCJRCKRSPwZ0RzMWmtLAhGvQyUAi9mXP/aFaGjJRQQiguHihMvcFMJUVUYlAMuHixPGy4en1WmVQqgHYHkuZjiEj6a2/LjtYzTY0eiZbgC37Mxh1UN3sn/dr6cCz/LHB/DJj9s+2oMdbtdz6TtfFwQHcMvOInfmQNjsgchNWLXmdfK6gyioAu/6uKrsm1kWLAciKuCuey5nYuXAh234bdmZ6INIUw4E/Ix49xtjCmXfzLL8nY/ktdgnAKwxxgIoXIyqmAOwvIqfiN0ALNd21HYBO9XXGMAdnZTYyHWzWjQAAAAASUVORK5CYII=";
@@ -1885,7 +1920,7 @@
const AFK_TIME = isDebug() ? 0 : 1000 * 5;
const PET_BOOST_DURATION = 1000 * 60 * 5;
const PET_MENU_COOLDOWN = 1000;
const URL_CHECK_INTERVAL = 250;
const URL_CHECK_INTERVAL = 150;
const HOP_DELAY = 500;
// Random event chances per tick
@@ -2025,7 +2060,7 @@
insertModal(`${birdBirb()} Mode`, message);
}),
new Separator(),
new MenuItem("2025.11.14.47", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.14.47"); }, false),
new MenuItem("2025.11.14.205", () => { alert("Thank you for using Pocket Bird! You are on version: 2025.11.14.205"); }, false),
];
const styleElement = document.createElement("style");
@@ -2142,31 +2177,6 @@
return;
}
// Preload font
const MONOCRAFT_SRC = "https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf";
const fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = `url(${MONOCRAFT_SRC}) format('opentype')`;
document.head.appendChild(fontLink);
// Add stylesheet font-face
const fontFace = `
@font-face {
font-family: 'Monocraft';
src: url(${MONOCRAFT_SRC}) format('opentype');
font-weight: normal;
font-style: normal;
}
`;
try {
const fontStyle = document.createElement("style");
fontStyle.textContent = fontFace;
document.head.appendChild(fontStyle);
} catch (e) {
error("Failed to load font: " + e);
}
load().then(onLoad);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 KiB

After

Width:  |  Height:  |  Size: 688 KiB

View File

@@ -0,0 +1,15 @@
const { Plugin, Notice } = require('obsidian');
module.exports = class PocketBird extends Plugin {
onload() {
console.log("Loading Pocket Bird version __VERSION__...");
const OBSIDIAN_PLUGIN = this;
__CODE__
console.log("Pocket Bird loaded!");
}
onunload() {
// Remove the birb when the plugin is unloaded
document.getElementById('birb')?.remove();
console.log('Pocket Bird unloaded!');
}
};

View File

@@ -0,0 +1,13 @@
// ==UserScript==
// @name Pocket Bird
// @namespace https://idreesinc.com
// @version __VERSION__
// @description It's a pet bird in your browser, what more could you want?
// @author Idrees
// @downloadURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
// @updateURL https://github.com/IdreesInc/Pocket-Bird/raw/refs/heads/main/dist/userscript/birb.user.js
// @match *://*/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// ==/UserScript==

View File

@@ -91,7 +91,7 @@ const UPDATE_INTERVAL = 1000 / 60; // 60 FPS
const AFK_TIME = isDebug() ? 0 : 1000 * 5;
const PET_BOOST_DURATION = 1000 * 60 * 5;
const PET_MENU_COOLDOWN = 1000;
const URL_CHECK_INTERVAL = 250;
const URL_CHECK_INTERVAL = 150;
const HOP_DELAY = 500;
// Random event chances per tick
@@ -348,31 +348,6 @@ Promise.all([
return;
}
// Preload font
const MONOCRAFT_SRC = "https://cdn.jsdelivr.net/gh/idreesinc/Monocraft@99b32ab40612ff2533a69d8f14bd8b3d9e604456/dist/Monocraft.otf";
const fontLink = document.createElement("link");
fontLink.rel = "stylesheet";
fontLink.href = `url(${MONOCRAFT_SRC}) format('opentype')`;
document.head.appendChild(fontLink);
// Add stylesheet font-face
const fontFace = `
@font-face {
font-family: 'Monocraft';
src: url(${MONOCRAFT_SRC}) format('opentype');
font-weight: normal;
font-style: normal;
}
`;
try {
const fontStyle = document.createElement("style");
fontStyle.textContent = fontFace;
document.head.appendChild(fontStyle);
} catch (e) {
error("Failed to load font: " + e);
}
load().then(onLoad);
}

View File

@@ -96,6 +96,7 @@ export function makeDraggable(element, parent = true, callback = () => { }, page
offsetX = touch.clientX - elementToMove.offsetLeft;
offsetY = touch.clientY - elementToMove.offsetTop;
e.preventDefault();
e.stopPropagation();
});
document.addEventListener("mouseup", (e) => {
@@ -136,8 +137,9 @@ export function makeDraggable(element, parent = true, callback = () => { }, page
/**
* @param {() => void} func
* @param {Element} [closeButton]
* @param {boolean} [allowEscape] Whether to allow closing with the Escape key
*/
export function makeClosable(func, closeButton) {
export function makeClosable(func, closeButton, allowEscape = true) {
if (closeButton) {
onClick(closeButton, func);
}
@@ -145,7 +147,7 @@ export function makeClosable(func, closeButton) {
if (closeButton && !document.body.contains(closeButton)) {
return;
}
if (e.key === "Escape") {
if (allowEscape && e.key === "Escape") {
func();
}
});

View File

@@ -41,6 +41,9 @@ export class StickyNote {
export function renderStickyNote(stickyNote, page, onSave, onDelete) {
const noteElement = makeElement("birb-window");
noteElement.classList.add("birb-sticky-note");
const color = getColor(stickyNote.id);
noteElement.style.setProperty("--birb-highlight", color);
noteElement.style.setProperty("--birb-border-color", color);
// Create header
const header = makeElement("birb-window-header");
@@ -77,7 +80,7 @@ export function renderStickyNote(stickyNote, page, onSave, onDelete) {
onDelete();
noteElement.remove();
}
}, closeButton);
}, closeButton, false);
}
if (textarea && textarea instanceof HTMLTextAreaElement) {
@@ -144,3 +147,14 @@ export function createNewStickyNote(stickyNotes, onSave, onDelete) {
stickyNotes.push(stickyNote);
onSave();
}
/**
* Get a color based on the mod of the sticky note ID
* @param {string} id
* @returns {string} A color hex code
*/
function getColor(id) {
const colors = ["#ff8baa", "#79bcff", "#d18bff", "#6de192", "#ffd17c", "#ffb37c", "#ff7c7c"];
const index = parseInt(id, 10) % colors.length;
return colors[index];
}

View File

@@ -1,3 +1,10 @@
@font-face {
font-family: 'Monocraft';
src: url("__MONOCRAFT_SRC__") format('opentype');
font-weight: normal;
font-style: normal;
}
:root {
--birb-border-size: 2px;
--birb-neg-border-size: calc(var(--birb-border-size) * -1);
@@ -318,6 +325,17 @@
.birb-sticky-note {
position: absolute;
box-sizing: border-box;
animation: fade-in 0.15s ease-in;
}
@keyframes fade-in {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.birb-sticky-note > .birb-window-content {
@@ -340,5 +358,6 @@
}
.birb-sticky-note-input:focus {
outline: none;
outline: none !important;
box-shadow: none !important;
}