Jason Brain's Tech Blog

From Prototype to Polish: Gematria Calculator v1.0.1 is Here!

by Jason Brain

 


A little while ago, I shared the initial version of my Gematria Calculator, a simple tool for decoding words with numerology. The response was fantastic, and it motivated me to transform that early prototype into a truly polished and full-featured application.

After a lot of work on the user experience and overall design, I'm thrilled to announce the official release of Gematria Calculator v1.0.1!

A Focus on Design and User Experience

My primary goal for this release was to create a design that is not only powerful but also a pleasure to use. The feedback was clear: the tool needed to be as intuitive as it was comprehensive. Here’s what’s new on the design front:

  • Modern & Responsive UI: The entire interface has been redesigned to be clean, modern, and fully responsive. Whether you're on a desktop or your phone, the experience is seamless.
  • Light & Dark Modes: The calculator now automatically detects your system's theme preference. Of course, you can always toggle between light and dark modes manually with the new theme switcher in the header.
  • Immersive Scrolling: To keep the focus on the content, the header and footer now intelligently hide as you scroll down and reappear when you scroll up, creating a distraction-free environment for your research.
  • Redesigned Systems Selector: The system selection is no longer just a list; it's a powerful and user-friendly overlay. You can now quickly select the base systems, select all, or clear your choices with dedicated buttons.

More Than Just a Pretty Face: Packed with Features

Beyond the visual overhaul, version 1.0.1 is packed with features that make it a robust tool for both newcomers and seasoned researchers:

  • Extensive System Support: The calculator now supports 28 different gematria systems, from core methods like Ordinal and Standard to more esoteric ones like Primes, Sumerian, and Alphanumeric Qabbala (AQ).
  • New Informational Resources: To make the tool more educational, I've added two new pages:
    • About Gematria: A detailed article on the history, meaning, and cultural significance of gematria.
    • Gematria Ciphers: A complete reference guide with value tables for every single supported system.
  • SEO & Social Sharing: The entire site has been optimized for search engines and social media. Sharing a link will now generate a rich, descriptive preview, making it easier to share your findings.

Try It Now and What's Next

This release establishes a solid foundation for the Gematria Calculator, and I'm excited for you to try it out.

This project has been a fantastic journey so far, and I'm already thinking about what's next. Have a feature you'd like to see or a system you'd like added? Feel free to open an issue on the GitHub repository.

Thank you for following along!


From Classic Hardware to Modern Code: Recreating the Denon DN-1000F CD Player in a Browser

by Jason Brain

A personal project that bridges the gap between a legendary piece of audio gear and the modern web.




The Sound of an Era

Every so often, a piece of technology comes to define an era. In the world of professional audio, the Denon DN-1000F was one of those devices. A classic CD player renowned for its reliability, intuitive design, and signature sound, it was a staple in DJ booths, radio stations, and music studios for decades.

But as technology marches forward, even the most beloved hardware can become obsolete. The rich, tactile experience of using a DN-1000F—setting a cue point with a physical button, adjusting pitch with a slider—is something that can't be replicated with a simple web based app.

Or can it?

I decided to find out. As a personal challenge and a tribute to this iconic machine, I set out to recreate the Denon DN-1000F not as a piece of hardware, but as a fully functional web application.



Meet the DN-1000F Web Emulator

The result is a web-based recreation of the Denon DN-1000F, built to bring the functionality and feel of this legendary device to any modern browser. No special hardware or software is required—just an audio file and your keyboard.

Key Features: A Modern Take on a Classic

My goal was to stay true to the original's core functionality while leveraging the power of the web. The emulator allows you to:

  • Load and Play Multiple Audio Files: Works with MP3, WAV, FLAC, and more.
  • Set and Jump to Cue Points: Precisely mark and return to specific points in a track.
  • Real-time Pitch Adjustment: Use the slider to adjust pitch from -10% to +10% for beat matching.
  • Toggle Time Display: Switch between elapsed and remaining track time, just like the original.
  • View Album Art: The emulator automatically reads and displays album art from embedded metadata.
  • Full Keyboard Support: Control every feature from your keyboard for a faster, more tactile workflow.

Responsive and Ready for Any Device

Whether you're on a desktop, tablet, or phone, the emulator is fully responsive and designed for a seamless experience. It’s perfect for DJs who want a practice tool, producers looking for a simple beat-matching solution, or anyone curious about the golden age of digital audio.

Under the Hood: The Technology

This project was a fantastic opportunity to work with some powerful web technologies. Here’s a brief look at the stack:

  • The Web Audio API is the heart of the application, handling all audio playback, pitch shifting, and timing.
  • The JavaScript Media Tags library is used to read metadata from audio files, allowing the display of album art and other track information.
  • The user interface is built with HTML5 and CSS3, with a custom design that emulates the look and feel of the original Denon hardware.
  • A Canvas-based waveform display provides a visual representation of the audio, making it easy to see what’s playing.

Try It for Yourself

I invite you to experience the emulator firsthand. You can try it directly in your browser by visiting the project's GitHub page. If you'd like to use it offline, you can simply save the index.html file.

👉 Try the Denon DN-1000F Web Emulator Here: [Link to DN-1000F Web Emulator]

What's Next?

This project is a living tribute, and I plan to continue improving it. Some future enhancements I have in mind include a dedicated mobile UI, integration with music libraries, and the ability to save cue points and pitch settings.

Let's Connect

Thank you for taking the time to read about my project. If you're interested in my work, I'd love to connect. You can follow it's journey and see what I'm building next here: 
https://github.com/jasonbra1n


If you'd like to contribute to the project, feel free to fork the repository, submit a pull request, or share it with your music-loving friends. I'm always open to collaboration and feedback. Here's the project link:
https://github.com/jasonbra1n/Denon-DN-1000F-Web-Emulator


Building BlueMountainDJ.com: A Modern Wedding DJ Website with Tailwind CSS and JavaScript

by Jason Brain

Building BlueMountainDJ.com: A Modern Wedding DJ Website with Tailwind CSS and JavaScript

As a web developer, I recently had the opportunity to create BlueMountainDJ.com, a single-page website for an award-winning DJ service in Blue Mountain, Ontario. This project was an exciting blend of modern web technologies, creative design, and user-focused functionality, all tailored to showcase a premium wedding and event entertainment business. In this post, I'll walk you through the technical highlights, design decisions, and key features that make this site stand out.

Project Overview

Blue Mountain DJ, led by industry veteran DJ Marty C., needed a website that reflected their 25+ years of experience and 10,000+ successful events. The goal was to create a visually engaging, responsive, and SEO-optimized site that would attract couples planning weddings, corporate event organizers, and party hosts. The site needed to highlight their services (DJ, photobooth, karaoke, lighting, and more) while providing an intuitive user experience and strong calls-to-action (CTAs).

I chose a tech stack of HTML, Tailwind CSS, and vanilla JavaScript, hosted on GitHub Pages, to deliver a lightweight, performant, and maintainable solution. Here's how I brought it to life.

Technical Highlights

1. Responsive Design with Tailwind CSS

To ensure the site looks stunning on all devices, I leveraged Tailwind CSS for its utility-first approach. Tailwind allowed rapid prototyping and consistent styling without writing excessive custom CSS. Key responsive features include:

  • Fluid Grid Layouts: Used Tailwind's grid system for sections like services (grid-cols-1 md:grid-cols-2 lg:grid-cols-3) and pricing packages (grid-cols-1 md:grid-cols-2 lg:grid-cols-4) to adapt seamlessly across screen sizes.
  • Mobile Navigation: A hamburger menu toggles a full-screen mobile menu with smooth transitions (transform: translateX) for smaller screens, while the desktop menu uses a flex layout.
  • Dynamic Typography: Combined Playfair Display for elegant headings and Inter for clean body text, with responsive font sizes (text-5xl md:text-7xl).

2. Engaging Hero Section with Video Background

The hero section is the centerpiece of BlueMountainDJ.com, featuring a looping video background (<video autoplay loop muted>) overlaid with a semi-transparent gradient (bg-black bg-opacity-50). This creates a cinematic feel that instantly grabs attention. I used CSS positioning and transforms to ensure the video scales correctly across devices, with a fallback gradient for accessibility.

Floating music note icons (<i class="fas fa-music music-note">) animate upward using CSS keyframes (@keyframes musicFloat), adding a playful nod to the DJ theme. The hero also includes trust badges and a scroll indicator to guide users to the next section.

3. Smooth Animations and Scroll Effects

To enhance user engagement, I implemented several animations:

  • Fade-In Effects: Sections use the IntersectionObserver API to trigger fade-in animations (opacity and translateY) as they enter the viewport, creating a polished reveal effect.
  • Stats Counter: The stats section animates numbers (e.g., "10,000+ Events") using JavaScript intervals, triggered only once when the section is visible to optimize performance.
  • Sticky CTA Button: A "Book Now" button appears after scrolling 200px (IntersectionObserver and scroll event listener) and hides when the contact form is in view, ensuring it doesn't obstruct key content.

4. Interactive Features

  • FAQ Toggles: FAQ items use vanilla JavaScript to toggle answers (classList.toggle('hidden')) with smooth transitions and chevron icon swaps (fa-chevron-down to fa-chevron-up).
  • Scroll-to-Top Button: A fixed button (position: fixed) appears after scrolling 300px, with a smooth scroll to the top using window.scrollTo.
  • Navbar Scroll Effect: The navigation bar transitions from transparent to a blurred, dark background (backdrop-filter: blur(10px)) on scroll, enhancing readability.

5. SEO and Schema Optimization

To boost search visibility, I implemented comprehensive SEO practices:

  • Meta Tags: Detailed <meta> tags for description, keywords, and Open Graph/Twitter Cards ensure rich social sharing previews.
  • JSON-LD Schema: A ProfessionalService schema provides structured data for search engines, including business details, address, and operating hours.
  • Canonical URL: Prevents duplicate content issues with <link rel="canonical">.
  • Semantic HTML: Proper use of <section>, <nav>, and ARIA attributes (aria-label) improves accessibility and crawlability.

6. Formspree Integration

The contact form uses Formspree for serverless form handling, with fields tailored for event inquiries (e.g., event date, guest count, package selection). JavaScript adds a loading state (fa-spinner) on submission to enhance user feedback.

7. Performance and Accessibility

  • Optimized Assets: The video background (event.mp4) is compressed for fast loading, with a fallback gradient for low-bandwidth scenarios.
  • Accessibility: Semantic HTML, ARIA attributes, and high-contrast text ensure inclusivity. Form fields include required attributes and clear labels.
  • Custom Scrollbar: A styled scrollbar (::-webkit-scrollbar) adds a subtle branded touch without compromising usability.

Design Choices

The design draws inspiration from modern event industry trends, with a focus on elegance and energy:

  • Color Palette: Gradients of blue, purple, and pink (from-blue-600 to-purple-600) reflect the vibrant, celebratory nature of DJ services, with yellow accents for CTAs.
  • Typography: Playfair Display adds sophistication to headings, while Inter ensures readability for body text.
  • Visual Hierarchy: Bold headings, spacious layouts, and animated CTAs guide users through the site, from the hero section to the contact form.
  • Micro-Interactions: Hover effects on cards (card-hover), buttons (glow-btn), and pricing packages (transform: scale) create a dynamic, engaging experience.

Challenges and Solutions

One challenge was balancing the video background's visual impact with performance. I optimized the video file and used playsinline to ensure compatibility on mobile devices. Another challenge was implementing smooth scroll behavior with a fixed navbar. I used scroll-padding-top: 80px and adjusted scrollTo offsets to account for the navbar height, ensuring accurate anchor navigation.

Key Features for Users

  • Service Showcase: Six service cards (Wedding DJ, Corporate Events, Photobooth, etc.) with icon animations and detailed lists.
  • Pricing Packages: Four tiered packages (Silver, Gold, Platinum, Diamond) with hover effects and a "Best Value" ribbon for the Platinum package.
  • Testimonials: Real client reviews with star ratings and gradient avatars for authenticity.
  • DJ Marty C. Section: Highlights the founder's credentials, with a glowing image effect and a quote block for personality.

Future Enhancements

The client could get me to add a photo gallery section using a lightbox plugin for event showcases. I could potentially integrate a booking calendar API for real-time availability checks. A blog section could also share DJ tips and event planning advice to boost engagement and SEO. 

Conclusion

Building BlueMountainDJ.com was a rewarding project that combined technical expertise with creative design. The site not only showcases a premier DJ service but also demonstrates the power of modern web technologies like Tailwind CSS and vanilla JavaScript to create a fast, accessible, and visually stunning experience. Check out the live site at BlueMountainDJ.com and let me know your thoughts!

Have you built a similar single-page site? I'd love to hear about your approach in the comments or connect on Twitter/X. If you're interested in a custom website for your business, feel free to reach out!

Tutorial: Installing OpenProject on Raspberry Pi Using Docker

by Jason Brain


 OpenProject is an open-source project management tool that works well on a Raspberry Pi (RPi) via Docker, provided you're using a 64-bit OS (like Raspberry Pi OS 64-bit) and a model with at least 4GB RAM (e.g., Pi 4 or Pi 5). This tutorial assumes you already have Docker installed and running on your RPi. If not, you can install it quickly with:


curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER

Log out and back in after the last command to apply group changes. We'll use the official all-in-one Docker container for a quick setup. This is ideal for testing or small-scale use, but for production, consider the Docker Compose method for better scalability.

Prerequisites

  • Raspberry Pi with 64-bit Raspberry Pi OS (Lite version recommended for efficiency).
  • At least 4GB RAM and a microSD card (16GB+ Class 10 or better).
  • Docker installed and running.
  • Access to your RPi's terminal (via SSH or directly).
  • Optional: An external drive (e.g., USB SSD) for persistent storage to avoid filling your SD card.

Step 0: Check the Latest OpenProject Version

OpenProject releases Docker images regularly. Check the latest stable version on Docker Hub:

docker search openproject/openproject

Or visit Docker Hub in a browser and look for the arm64 tag (e.g., 16 as of late 2024). Use the highest number available that's tagged for ARM64

Step 1: Verify Docker is Running

Ensure Docker is active:

sudo systemctl status docker

If not running, start it:

sudo systemctl start docker
Step 2: Create Directories for Persistent Storage

Create folders to store OpenProject’s database and assets (to persist data across container restarts). To prevent data loss on container restarts, create directories for the database and assets. Use an external drive if possible (e.g., mounted at /mnt/usb).

sudo mkdir -p /var/lib/openproject/{pgdata,assets}
sudo chown -R 1000:1000 /var/lib/openproject

If using an external drive (e.g., mounted at /mnt/usb):

sudo mkdir -p /mnt/usb/openproject/{pgdata,assets}
sudo chown -R 1000:1000 /mnt/usb/openproject

Step 3: Pull and Run the OpenProject Docker Container

Run the following command to pull and start the OpenProject container. Replace:

  • 192.168.1.100 with your Raspberry Pi’s IP address (find it with hostname -I).
  • secret with a strong key (generate with openssl rand -hex 32).
  • 16 with the latest version (check Docker Hub for arm64 tags; as of late 2024, 16 is recent).
 docker run -d \
  -p 8080:80 \
  --name openproject \
  -e OPENPROJECT_SECRET_KEY_BASE=secret \
  -e OPENPROJECT_HOST__NAME=192.168.1.100:8080 \
  -e OPENPROJECT_HTTPS=false \
  -e OPENPROJECT_DEFAULT__LANGUAGE=en \
  -v /var/lib/openproject/pgdata:/var/openproject/pgdata \
  -v /var/lib/openproject/assets:/var/openproject/assets \
  openproject/openproject:16
Explanation:
  • -p 8080:80: Maps port 8080 on your Pi to the container’s port 80.
  • -e: Sets environment variables (host, no HTTPS, English language).
  • -v: Links persistent storage.
  • -d: Runs in the background.

The image will download (may take a few minutes). Check progress:

docker logs -f openproject

Wait for messages like "Database configuration done" and "Memcached configuration done."

Step 4: Access OpenProject

  • Open a browser on any device on your network.
  • Navigate to http://<your-pi-ip>:8080 (e.g., http://192.168.1.100:8080).
  • Log in with:
    • Username: admin
    • Password: admin
  • Change the password immediately after logging in.

Step 5: Verify Installation

If the web interface loads and you can log in, the installation is successful. Configure settings (e.g., email) via Admin > Emails & Notifications.

Troubleshooting

  • Port Conflict: If 8080 is in use, change to another port (e.g., -p 8081:80) and update OPENPROJECT_HOST__NAME.
  • ARM64 Issues: Ensure your OS is 64-bit (uname -m should return aarch64). Use an -arm64 tagged image if available.
  • Slow Startup: Raspberry Pi’s limited resources may slow initialization. Monitor with docker stats.

If you encounter errors, share the output of docker logs openproject for further assistance. For advanced setups (e.g., separate database), consider Docker Compose as mentioned previously, but this single-container method is simplest for getting started.

This setup gives you a fully functional OpenProject instance for local project management. For more config options, check the official docs.



Updating Raspberry Pi OS Bookworm: Handling the initramfs.conf Prompt

by Jason Brain


My First Time Updating a Raspberry Pi with apt update

Updating a Raspberry Pi for the first time can feel like a rite of passage for anyone diving into the world of single-board computers. The Raspberry Pi, running a Linux-based operating system like Raspberry Pi OS, relies on tools like apt to keep its software fresh and secure. In this post, I’ll walk you through my experience performing my first apt update and apt upgrade, including a moment of decision when I encountered a configuration file prompt, what I learned by checking the differences, and how I wrapped it all up with a cleanup command.

Step 1: Opening the Terminal

I started by opening the terminal on my Raspberry Pi. If you’re using the graphical interface, you can find the terminal in the menu or press Ctrl + Alt + T. If you’re working over SSH or on a headless setup, you’re already in the right place.

Step 2: Running apt update

To begin, I ran the following command to update the package lists for upgrades and new package installations:

sudo apt update

The sudo part is necessary because updating the system requires superuser privileges. This command refreshes the list of available packages and their versions from the repositories. After running it, I saw lines showing the system fetching data, ending with a summary like “All packages are up to date” or a list of packages that could be upgraded.

Step 3: Running apt upgrade

Next, I wanted to install the available updates, so I ran:

sudo apt upgrade

This command downloads and installs the latest versions of the packages. Progress bars showed downloads and installations in action, but then I hit a prompt that made me pause.

Step 4: The Configuration File Prompt

During the upgrade, I encountered this message:

Configuration file '/etc/initramfs-tools/initramfs.conf'
 ==> Modified (by you or by a script) since installation.
 ==> Package distributor has shipped an updated version.
   What would you like to do about it ?  Your options are:
    Y or I  : install the package maintainer's version
    N or O  : keep your currently-installed version
      D     : show the differences between the versions
      Z     : start a new shell to examine the situation
 The default action is to keep your current version.
*** initramfs.conf (Y/I/N/O/D/Z) [default=N] ?

This prompt indicated that the initramfs.conf file, part of the initramfs-tools package used to generate the initial ramdisk for booting, had been modified since installation. The package maintainer provided a new version, and I needed to decide what to do.

Understanding the Options

Here’s what I learned about the options:

  • Y or I: Install the package maintainer’s new version, overwriting my current file. This ensures the latest configuration but might discard custom changes.
  • N or O: Keep my current version, preserving modifications but potentially missing updates or fixes.
  • D: Show the differences between the two versions, useful for comparing changes.
  • Z: Open a shell to investigate further, ideal for advanced users.

Since this was my first update and I hadn’t intentionally modified initramfs.conf, I was curious about the changes. I first selected D to view the differences.

Step 5: Analyzing the Differences

Selecting D showed a diff between my current file (/etc/initramfs-tools/initramfs.conf) and the maintainer’s new version (/etc/initramfs-tools/initramfs.conf.dpkg-new). Here’s what I saw:

--- /etc/initramfs-tools/initramfs.conf 2025-05-12 20:17:48.163045799 -0400
+++ /etc/initramfs-tools/initramfs.conf.dpkg-new 2025-07-21 03:33:02.000000000 -0400
@@ -17,7 +17,7 @@
 # list - Only include modules from the 'additional modules' list
 #

-MODULES=dep
+MODULES=most

 #
 # BUSYBOX: [ y | n | auto ]
@@ -74,11 +74,11 @@
 #
 # RUNSIZE: ...
 #
-# The size of the /run tmpfs mount point, like 256M or 10%
+# The size of the /run tmpfs mount point, like 256M or 20%
 # Overridden by optional initramfs.runsize= bootarg
 #

-RUNSIZE=10%
+RUNSIZE=20%

Breaking Down the Changes

The diff revealed two changes:

  1. MODULES: Changed from dep to most.
    • dep means the initramfs includes only modules needed for the specific hardware, keeping the initramfs small.
    • most includes a broader set of modules, ensuring compatibility with a wider range of hardware but increasing the initramfs size.
  2. RUNSIZE: Changed from 10% to 20%.
    • This setting controls the size of the /run tmpfs mount point, used for temporary files during boot. Increasing it to 20% allocates more memory, potentially improving performance for systems needing more temporary storage during boot.

Since I hadn’t made these changes myself, they were likely made by a script or another package. The maintainer’s version seemed to prioritize broader compatibility (MODULES=most) and more memory allocation (RUNSIZE=20%), which made sense for a general-purpose update.

My Decision: Choosing “Yes”

After reviewing the diff, I chose Y to install the package maintainer’s version. I typed Y and pressed Enter. My reasoning was that I hadn’t customized initramfs.conf intentionally, and the changes (broader module support and increased tmpfs size) were likely beneficial for stability and compatibility with the updated system. If I had specific hardware constraints or custom boot settings, I might have chosen N to keep my version or merged changes manually after selecting Z, but Y was the safest choice for a beginner like me.

The upgrade continued, installing the new version of the configuration file and completing the package updates without further prompts.

Step 6: Cleaning Up with apt autoremove

Once the upgrade finished, I wanted to clean up unneeded packages to free up space. I ran:

sudo apt autoremove

This command removes packages that were automatically installed as dependencies but are no longer required. It freed up some disk space, which is especially helpful on a Raspberry Pi with limited storage.

Step 7: Verifying the Update

To ensure everything was applied correctly, I rebooted my Raspberry Pi with:

sudo reboot

After rebooting, I checked that my system was running smoothly. Everything worked as expected, confirming the update was successful.

Key Takeaways

  • Run sudo apt update first to refresh package lists, then sudo apt upgrade to install updates.
  • Configuration file prompts like the one for initramfs.conf are normal. Use D to inspect differences, which can help you decide between Y (maintainer’s version) or N (keep yours).
  • The diff for initramfs.conf showed changes to MODULES (from dep to most) and RUNSIZE (from 10% to 20%), which improve compatibility and allocate more memory for boot processes.
  • Choosing Y is often safe for beginners if you haven’t customized the file.
  • Clean up with sudo apt autoremove to remove unneeded packages.
  • Reboot after updates to ensure changes take effect.

Updating my Raspberry Pi was a learning experience, especially with the configuration file prompt. Checking the differences with D gave me confidence in choosing Y, and the cleanup command kept my system tidy. I hope this guide helps other first-timers navigate their Raspberry Pi updates with ease!

Blogger: Google Code Prettify

by Jason Brain

To set up Google Code Prettify on your Blogger blog for syntax highlighting, follow these steps:

Add the Prettify CSS and JavaScript

  • Go to your Blogger Dashboard.
  • Navigate to Theme > Edit HTML.
  • Find the <head> section of your template.

Insert the following lines just before the closing </head> tag:


<link href='https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/prettify.css' rel='stylesheet'/>
<script src='https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js'></script>

Use Code Blocks in Your Posts 

  • When writing a blog post, switch to the HTML view (click "HTML" in the post editor). 
  • Wrap your code using <pre> and <code> tags, and add the prettyprint class:
 

<pre class="prettyprint">
<code>
function helloWorld() {
  console.log("Hello, world!");
}
</code>
</pre>  

3. Optional: Specify Language for Better Parsing You can help Prettify detect the language by adding a language class:

<pre class="prettyprint lang-js">
<code>
// JavaScript code
var x = 42;
</code>
</pre> 

Common language classes:

  • lang-js – JavaScript 
  • lang-html – HTML/XML 
  • lang-css – CSS 
  • lang-python – Python 
  • lang-java – Java 

Handle Unescaped HTML in Code Blocks

If your code contains unescaped HTML characters (e.g., <, >, &), Prettify may not render them correctly. To fix this, add the following script just before the closing tag to automatically escape these characters within tags, while avoiding double-escaping already escaped entities:

WOKING ON IT << the Challenge

This script runs after the page loads, finds all <code> elements within <pre class="prettyprint">, and converts unescaped HTML characters to their proper entities before Prettify processes them. .

Preview and Publish 

  • Preview your post to ensure code is highlighted correctly.
  •  Publish when satisfied.

 ✅ Tips:

  • Prettify automatically highlights all elements with class="prettyprint" on page load—no extra JavaScript needed. 
  • Escape your code. <. > and & all cause challenges with blogger, so showing code is a challenge, creating a script to do that for us is even more of a challenge. 
  • For dark themes, you can replace the CSS link with a themed version (e.g., sons-of-obsidian.css):

<link href='https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/skins/sons-of-obsidian.css' rel='stylesheet'/> 

Now your code snippets will be cleanly formatted and syntax-highlighted using Google Code Prettify.

Blogger: Scroll‑To‑Top Button

by Jason Brain
Below is a complete, copy‑and‑paste ready snippet that you can drop into any Blogger (blogspot) XML template.


It creates a small “scroll‑to‑top” button that sits in the lower‑right corner of the screen and fades in/out as you scroll.

How to add it


Open your Blogger dashboard → Theme → Edit HTML.
In the template editor, find the closing </body> tag (or any place before it).
Paste the entire block that starts with <style> and ends with </script> right before </body>.
Save your theme.
The code uses only vanilla JavaScript, so no external libraries are required.

<!-- ======== Scroll-to-Top Button ======== -->
<style>
  /* The button itself */
  #scrollToTopBtn {
    position: fixed;
    bottom: 30px;          /* distance from the bottom of viewport */
    right: 30px;           /* distance from the right side of viewport */
    z-index: 9999;         /* stay on top of everything else */
    width: 48px;
    height: 48px;
    border-radius: 50%;    /* make it circular */
    background-color: #555;/* default colour – change as needed */
    color: white;
    font-size: 24px;
    line-height: 48px;     /* vertical centering of the icon */
    text-align: center;
    cursor: pointer;
    opacity: 0;            /* start hidden */
    transition: opacity .4s ease-in-out, background-color .3s;
    box-shadow: 0 2px 6px rgba(0,0,0,.3);
  }
  #scrollToTopBtn:hover {
    background-color: #333;/* darker on hover */
  }
  /* Show the button when it has class 'show' */
  #scrollToTopBtn.show { opacity: 1; }
</style>

<div id="scrollToTopBtn" title="Back to top">&#8679;</div> <!-- ▲ or &#x21E7; -->

<script>
(function(){
  var btn = document.getElementById('scrollToTopBtn');

  // Show/hide button based on scroll position
  window.addEventListener('scroll', function() {
    if (window.pageYOffset > 300) {   // show after scrolling down 300px
      btn.classList.add('show');
    } else {
      btn.classList.remove('show');
    }
  });

  // Smooth scroll to top when button is clicked
  btn.addEventListener('click', function() {
    window.scrollTo({top:0, behavior:'smooth'});
  });
})();
</script>
<!-- ======== End of Scroll-to-Top Button ======== -->

What each part does Section


Section Purpose
CSS (#scrollToTopBtn) Styles the button: fixed position, circle, colors, transition effects.
HTML (<div>) The actual button element. Uses a Unicode arrow (&#8679; ▲). You can swap it for an image or Font Awesome icon if you prefer.
JavaScript 1. Listens to scroll events – shows the button after scrolling past 300 px, hides it otherwise.
2. On click, smoothly scrolls back to the top of the page.

Customisation tips

  • Button colour: change background-color in the CSS block.
  • Size/position: modify bottom, right, width, height.
  • Scroll threshold: adjust the number 300 in the script if you want it to appear earlier/later.
  • Icon: replace the arrow with an image or Font Awesome icon by editing the innerHTML of #scrollToTopBtn.
That’s all! Your Blogger site will now have a tidy, responsive scroll‑to‑top button that works on desktop and mobile.