feat: add dynamic tag filtering and rewrite Wasm post
Some checks are pending
Deploy Hugo site to Pages / build (push) Waiting to run
Deploy Hugo site to Pages / deploy (push) Blocked by required conditions

This commit is contained in:
Divyam Ahuja 2026-05-09 20:41:42 +05:30
parent 495497b2e7
commit f327c33e9b
5 changed files with 200 additions and 39 deletions

View file

@ -280,6 +280,75 @@ img {
border-bottom-color: var(--accent); border-bottom-color: var(--accent);
} }
.post-list-info {
display: flex;
flex-direction: column;
gap: 0.2rem;
}
.post-list-tags {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.post-list-tag {
color: var(--accent-dim);
font-size: 0.8rem;
}
.post-list-tag:hover {
color: var(--accent);
}
/* --- Tags Cloud --- */
.tags-cloud {
display: flex;
flex-wrap: wrap;
gap: 1rem;
margin-top: 1.5rem;
}
.tag-item {
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.4rem 0.8rem;
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--fg);
font-size: 0.9rem;
transition: all var(--transition);
}
.tag-item:hover {
border-color: var(--accent);
background: var(--bg-hover);
color: var(--accent);
transform: translateY(-2px);
}
.tag-item.active {
border-color: var(--accent);
background: var(--accent-glow);
color: var(--accent);
}
button.tag-item {
cursor: pointer;
font-family: inherit;
}
.hidden {
display: none !important;
}
.tag-count {
color: var(--fg-dim);
font-size: 0.8rem;
}
/* Year group */ /* Year group */
.year-heading { .year-heading {
font-size: 1.1rem; font-size: 1.1rem;

View file

@ -2,45 +2,41 @@
title: "Hello WebAssembly: Getting Started with C/C++" title: "Hello WebAssembly: Getting Started with C/C++"
date: 2023-11-21T06:40:48Z date: 2023-11-21T06:40:48Z
draft: false draft: false
tags: ["WebAssembly", "C", "C++", "Emscripten", "WASM"] tags: ["WebAssembly", "C", "C++", "Emscripten"]
--- ---
WebAssembly (often abbreviated as wasm) is a binary instruction format for a stack-based virtual machine. It's designed as a portable compilation target for programming languages, enabling deployment on the web for client and server applications. The power of WebAssembly lies in its ability to execute code at near-native speed, opening up a world of possibilities for web applications. Lets dive deep into setting up the tools and writing our first WebAssembly module using C. If you've spent any time working on performance-critical web applications, you've probably hit the performance ceiling of JavaScript. I ran into this heavily during my Google Summer of Code project working on Chromium's audio processing pipeline. We needed near-native speeds to process audio without stuttering, and standard JavaScript just wasn't going to cut it.
## What is WebAssembly? Enter **WebAssembly** (Wasm).
WebAssembly acts as a bridge between high-performance code written in languages like C, C++, or Rust, and the web. Traditional web applications run entirely on JavaScript, which, while powerful, might not be the most efficient language for computationally intensive tasks. WebAssembly provides a fast, low-level binary format that browsers can execute, bringing near-native performance to web applications. WebAssembly is essentially a low-level binary format that runs directly in the browser at near-native speeds. It lets us write code in systems languages like C, C++, or Rust, compile it, and run it right alongside our JavaScript.
## Prerequisites Today, I want to walk you through the absolute basics: taking a simple C program and running it in your browser.
To embark on our WebAssembly journey, we need a set of tools to compile our C/C++ code into wasm format. The primary toolchain for this task is Emscripten. Emscripten compiles C/C++ code into WebAssembly and generates the necessary JavaScript and HTML glue code for seamless integration into web applications. ## The Magic Tool: Emscripten
### Setting Up Emscripten To bridge the gap between C/C++ and the web, we need a toolchain. The undisputed heavyweight champion here is **Emscripten**. It takes your C/C++ code, compiles it into a `.wasm` binary, and even generates the JavaScript "glue" code needed to load it into the browser.
The first step is setting up Emscripten. Open your terminal and follow these commands: Let's get it installed. Open your terminal and run:
```bash ```bash
# Clone Emscripten SDK repository # Clone the Emscripten SDK
git clone https://github.com/emscripten-core/emsdk.git git clone https://github.com/emscripten-core/emsdk.git
# Enter the cloned directory
cd emsdk cd emsdk
# Install the latest Emscripten tools # Fetch and install the latest tools
./emsdk install latest ./emsdk install latest
# Activate the installed tools # Make them active
./emsdk activate latest ./emsdk activate latest
# Source the environment variables for your current terminal session # Load the environment variables (you'll need to do this for new terminal sessions)
source ./emsdk_env.sh source ./emsdk_env.sh
``` ```
With Emscripten installed and configured, we're ready to write and compile our C code. ## Writing some C Code
## Writing C Code Let's not overcomplicate things for our first run. Create a file called `hello.c`:
Let's keep it simple for our first WebAssembly module. Create a file named `hello.c` with the following content:
```c ```c
#include <stdio.h> #include <stdio.h>
@ -51,40 +47,38 @@ int main() {
} }
``` ```
This C program simply prints a classic greeting to the standard output. Now, the magic happens when we compile this code using Emscripten. It doesn't get much simpler than that. But how do we get this to run in Chrome or Firefox?
## Compiling to WebAssembly ## Compiling to Wasm
In your terminal, navigate to the directory containing your `hello.c` file and execute the following command: With our Emscripten environment active, we can use `emcc` (the Emscripten Compiler Frontend). In the same directory as your `hello.c` file, run:
```bash ```bash
emcc hello.c -o hello.html emcc hello.c -o hello.html
``` ```
Let's break down this command: Here is what's happening under the hood:
- `emcc` is our compiler.
- `-o hello.html` tells Emscripten that we don't just want the raw binary; we want an HTML file we can actually open.
- `emcc`: The Emscripten Compiler Frontend. If you look at your directory now, Emscripten generated three files: `hello.wasm` (the actual compiled binary), `hello.js` (the JavaScript glue code to load the binary), and `hello.html` (a basic webpage to display the output).
- `hello.c`: Your input C file.
- `-o hello.html`: The output flag specifying that we want an HTML file. Emscripten will not only generate the WebAssembly binary (`hello.wasm`) but also the necessary JavaScript and HTML code (`hello.js` and `hello.html`) to run it in a browser.
Once the compilation is complete, you should find three new files in your directory: `hello.wasm`, `hello.js`, and `hello.html`. ## Running the Code
## Running the WebAssembly Module Because browsers have strict security policies around loading local files via JavaScript, you can't just double-click `hello.html`. We need to serve it over a local web server.
Now, let's see our WebAssembly module in action. Since browsers restrict fetching local files for security reasons, it's recommended to serve the generated files via a local server. Python makes this super easy:
You can use a simple tool like Python's `http.server` or `live-server` for this purpose. Let's use Python:
```bash ```bash
python3 -m http.server python3 -m http.server
``` ```
Open your web browser and navigate to `http://localhost:8000/hello.html`. You should see a webpage displaying the output of our C program: "Hello, WebAssembly!". Now, open your browser and head to `http://localhost:8000/hello.html`. If everything went according to plan, you'll see a terminal-like console on the webpage printing: `Hello, WebAssembly!`.
## Conclusion ## Wrapping up
We've covered the basics of WebAssembly, installed the necessary toolchain (Emscripten), written a simple C program, and successfully compiled and executed it in a web browser. This is obviously just the tip of the iceberg. Printing a string is fun, but the real power of WebAssembly comes from porting massive C++ codebases (like audio engines, physics simulators, or databases) directly into the browser.
This is just the tip of the iceberg. WebAssembly opens the door to porting complex applications, games, and libraries to the web, pushing the boundaries of what is possible in the browser. In future posts, we'll explore more advanced topics, including passing data between JavaScript and WebAssembly, handling memory, and optimizing code for the web. In future posts, I'll dive into more realistic use cases—like how I used Wasm and WebWorkers to build lock-free ring buffers for Chromium, passing complex memory structures back and forth between JavaScript and C++.
Happy coding with WebAssembly! Until then, happy hacking!

View file

@ -3,6 +3,16 @@
{{- if eq .Section "posts" }} {{- if eq .Section "posts" }}
{{/* Blog archive listing */}} {{/* Blog archive listing */}}
<div class="tag-filter-container">
<div class="tags-cloud" style="margin-top: 0.5rem; margin-bottom: 2.5rem;">
<button class="tag-item active" data-filter="all">All</button>
{{- range $name, $taxonomy := .Site.Taxonomies.tags }}
<button class="tag-item" data-filter="{{ $name | urlize }}">#{{ $name }} <span class="tag-count">({{ len $taxonomy }})</span></button>
{{- end }}
</div>
</div>
{{- $posts := .Pages -}} {{- $posts := .Pages -}}
{{- $byYear := $posts.GroupByDate "2006" -}} {{- $byYear := $posts.GroupByDate "2006" -}}
{{- range $byYear }} {{- range $byYear }}
@ -10,16 +20,95 @@
<h3 class="year-heading">{{ .Key }}</h3> <h3 class="year-heading">{{ .Key }}</h3>
<ul class="post-list"> <ul class="post-list">
{{- range .Pages }} {{- range .Pages }}
<li class="post-list-item"> {{- $tagList := slice -}}
{{- range .Params.tags -}}
{{- $tagList = $tagList | append (. | urlize) -}}
{{- end -}}
<li class="post-list-item" data-tags="{{ delimit $tagList "," }}">
<time class="post-date" datetime="{{ .Date.Format "2006-01-02" }}"> <time class="post-date" datetime="{{ .Date.Format "2006-01-02" }}">
{{ .Date.Format "02 Jan" }} {{ .Date.Format "02 Jan" }}
</time> </time>
<a href="{{ .Permalink }}" class="post-title-link">{{ .Title }}</a> <div class="post-list-info">
<a href="{{ .Permalink }}" class="post-title-link">{{ .Title }}</a>
{{- with .Params.tags }}
<span class="post-list-tags">
{{- range . }}
<a href="/posts/?tag={{ . | urlize }}" class="post-list-tag">#{{ . }}</a>
{{- end }}
</span>
{{- end }}
</div>
</li> </li>
{{- end }} {{- end }}
</ul> </ul>
</div> </div>
{{- end }} {{- end }}
<script>
document.addEventListener('DOMContentLoaded', () => {
const filterButtons = document.querySelectorAll('.tag-filter-container .tag-item');
const postItems = document.querySelectorAll('.post-list-item');
const archiveYears = document.querySelectorAll('.archive-year');
function applyFilter(filterValue) {
// Find and activate the correct button
let targetButton = Array.from(filterButtons).find(btn => btn.getAttribute('data-filter') === filterValue);
if (!targetButton) targetButton = filterButtons[0]; // fallback to 'all'
filterButtons.forEach(btn => btn.classList.remove('active'));
targetButton.classList.add('active');
const filter = targetButton.getAttribute('data-filter');
// Filter posts
postItems.forEach(item => {
if (filter === 'all') {
item.classList.remove('hidden');
} else {
const tags = item.getAttribute('data-tags') ? item.getAttribute('data-tags').split(',') : [];
if (tags.includes(filter)) {
item.classList.remove('hidden');
} else {
item.classList.add('hidden');
}
}
});
// Hide empty years
archiveYears.forEach(yearDiv => {
const visiblePosts = yearDiv.querySelectorAll('.post-list-item:not(.hidden)');
if (visiblePosts.length === 0) {
yearDiv.classList.add('hidden');
} else {
yearDiv.classList.remove('hidden');
}
});
}
filterButtons.forEach(button => {
button.addEventListener('click', () => {
applyFilter(button.getAttribute('data-filter'));
// Update URL without reloading
const url = new URL(window.location);
if (button.getAttribute('data-filter') === 'all') {
url.searchParams.delete('tag');
} else {
url.searchParams.set('tag', button.getAttribute('data-filter'));
}
window.history.pushState({}, '', url);
});
});
// Check URL params on load
const urlParams = new URLSearchParams(window.location.search);
const initialTag = urlParams.get('tag');
if (initialTag) {
applyFilter(initialTag);
}
});
</script>
{{- else }} {{- else }}
{{/* Generic page content */}} {{/* Generic page content */}}
<div class="post-content"> <div class="post-content">

View file

@ -10,7 +10,7 @@
<span class="separator">|</span> <span class="separator">|</span>
<span class="post-tags"> <span class="post-tags">
{{- range . }} {{- range . }}
<a href="{{ "tags/" | absURL }}{{ . | urlize }}/" class="post-tag">#{{ . }}</a> <a href="/posts/?tag={{ . | urlize }}" class="post-tag">#{{ . }}</a>
{{- end }} {{- end }}
</span> </span>
{{- end }} {{- end }}

View file

@ -24,7 +24,16 @@
<time class="post-date" datetime="{{ .Date.Format "2006-01-02" }}"> <time class="post-date" datetime="{{ .Date.Format "2006-01-02" }}">
{{ .Date.Format "02 Jan" }} {{ .Date.Format "02 Jan" }}
</time> </time>
<a href="{{ .Permalink }}" class="post-title-link">{{ .Title }}</a> <div class="post-list-info">
<a href="{{ .Permalink }}" class="post-title-link">{{ .Title }}</a>
{{- with .Params.tags }}
<span class="post-list-tags">
{{- range . }}
<a href="/posts/?tag={{ . | urlize }}" class="post-list-tag">#{{ . }}</a>
{{- end }}
</span>
{{- end }}
</div>
</li> </li>
{{- end }} {{- end }}
</ul> </ul>