Tell us what works and what could be better. We read every submission.
@angusgrant·47 public vizzes
Seven Seas is a pirate-themed travel app with a Treasure Chest home page and a Dice Games page. The app uses JavaScript classes and custom elements to track loot and power interactive dice rolls. On the main page, the TreasureChest class manages bronze, silver, and gold counts and emits custom events when treasure is added. The Dice Games page uses a custom <roll-dice> Web Component with shadow DOM, featuring a roll button and an accessible aria-live region that announces results like "You rolled a 4." The design uses pirate emoji, a seafaring theme, and a service worker for offline support.
Seven Seas is a pirate-themed travel app that lets users collect and track treasure across gold, silver, and bronze. The main page displays the current loot total, which persists in localStorage, while a Dice Games page lets visitors roll dice for fun. A separate Treasure Chest page uses a TreasureChest class to add coins and update the loot counter through custom events. The visualization demonstrates state management, localStorage persistence, and interactive UI patterns in a playful pirate setting.
Seven Seas is a playful interactive demonstration of custom web components built with JavaScript classes and the Shadow DOM API. The visualization combines a RollDice element, which shuffles an array of die faces and announces the result via an aria-live region for accessibility, with a TreasureChest class that tracks accumulated bronze, silver, and gold loot through a chainable API and custom events. When a user clicks the roll button, the dice component updates the displayed result, and the treasure chest accumulates values through its add methods, emitting events that could be used to trigger visual updates. The example showcases how encapsulated web components and event-driven architecture can create a simple game-like interaction, with the dice roll outcome feeding into the treasure collection system. Styling is handled with CSS custom properties for flexibility.
This example demonstrates JavaScript ES Modules by simulating dice rolls in the browser console. It imports the `d6` and `d20` functions from a separate `roll.js` module, then logs the results of rolling a six-sided and twenty-sided die. The module defines dice size arrays and uses a Fisher-Yates shuffle algorithm to randomly select a value from each array. The page itself displays only a heading and brief instruction, with all output occurring in the developer console.
This example demonstrates how JavaScript ES Modules enable code reuse by separating dice-rolling logic into an external file. The page imports the `d6` and `d20` functions from `roll.js`, rolls one six-sided and one twenty-sided die, and logs the results to the browser console. The `roll.js` module defines dice arrays and uses a shuffle function to randomly select values, exporting seven dice types (`d2` through `d20`). The HTML file contains only minimal styling and a script tag with `type="module"`, highlighting the modular import/export pattern without any visual output.
A custom element named `roll-dice` demonstrates the Shadow DOM, rendering a button and an `aria-live` message region within a closed shadow root. The component shuffles an array of dice values and displays the result on click, using the `attachShadow()` API and custom element lifecycle callbacks. External styling applies CSS custom properties and `::part(btn)` selectors to alter the button’s appearance, including a lurid variant. The example shows how Shadow DOM encapsulates structure while enabling targeted style customization through exposed parts.
A custom `<roll-dice>` element displays a button labeled "Roll a D6" and a live region for results. Clicking the button shuffles a fixed array of numbers 1 through 6 and reports the first value as the roll outcome. The example demonstrates the Shadow DOM API, using `attachShadow` with a closed mode, a `<slot>` for the button label, and private class fields for encapsulation. It also relies on the Custom Elements lifecycle callbacks `connectedCallback` and `disconnectedCallback` to manage event listeners.
This example demonstrates a custom web component called `roll-dice` that simulates rolling a six-sided die. The component displays a button and an accessible live region; clicking the button triggers a shuffle of the dice sides array, and the resulting value is announced in the `aria-live` region. It uses the custom elements API via `HTMLElement` and `customElements.define`, with a static private shuffle method that implements the Fisher–Yates algorithm. No external libraries are used; the behavior is self-contained in the component’s constructor and callbacks.
This example demonstrates a custom web component that renders a dice-rolling button and an accessible output area. The component, defined as `roll-dice`, uses the `HTMLElement` class and the `customElements.define` API to encapsulate its template, which includes a button with customizable text and a `div` with an `aria-live` attribute for screen-reader announcements. The component dynamically replaces its original content with this structure upon instantiation, supporting multiple instances on a page. No dice-rolling logic is implemented; only the component’s markup and lifecycle setup are shown.
This example demonstrates a JavaScript class called `TreasureChest` that manages private bronze, silver, and gold coin counts, along with a customizable loot message. The code uses ECMAScript private class features (denoted by `#` prefixes) for instance properties and methods, including a static `#shuffle` utility and an `#emit` method that dispatches custom events like `treasure:bronze`. Public methods such as `addBronze`, `addSilver`, and `addGold` update the private values and trigger events, while `getLoot` returns a formatted string with the current totals. The interaction is intended to occur through the browser’s console, with no visual rendering or external data sources.
This example demonstrates JavaScript’s private class features using a `TreasureChest` class. It shows how to encapsulate properties like `#bronze`, `#silver`, and `#gold` with methods such as `addBronze`, `getGold`, and `getLoot`, while a private static `#shuffle` method randomly selects loot types and amounts. The code relies on native ECMAScript class syntax and the `Object.assign` method for merging options. All interaction happens in the browser console, where the user can instantiate the class and call its public methods.
This example demonstrates a JavaScript class called `TreasureChest` that models a collection of gold, silver, and bronze coins. It shows how to initialize the chest with default values, add coins of each type using chainable methods like `addGold`, `addSilver`, and `addBronze`, and retrieve a summary via `getLoot`. A static `getRandomLoot` method uses a private `#shuffle` function to assign random coin counts. The visualization itself is minimal, with all interaction occurring through the browser console, using native JavaScript class syntax and no external libraries.
Treasure Chest is a JavaScript demonstration that uses a custom `TreasureChest` class to track quantities of gold, silver, and bronze. The page shows a simple HTML template with a heading, but all interactive behavior occurs in the browser console. Users can instantiate the class, add coins using methods like `addGold`, `addSilver`, and `addBronze`, and retrieve totals with `getLoot`. The class also includes a `getRandomLoot` static method that relies on a custom `shuffle` function to generate random coin amounts. The code uses native JavaScript object methods and property descriptors.
Treasure Chest demonstrates a JavaScript module pattern for managing a virtual loot inventory. The page loads with a simple header and paragraph, while all functionality occurs through the console using the custom `TreasureChest` constructor object. This object tracks gold, silver, and bronze counts, offering methods like `addGold`, `addSilver`, and `addBronze` for incrementing values, plus `getLoot` to report totals. A `getRandomLoot` method uses a Fisher–Yates shuffle algorithm to generate randomized loot amounts from 1 to 50. The code employs no external libraries, relying purely on native JavaScript syntax and prototype-based inheritance.
A JavaScript constructor function called TreasureChest tracks running totals for gold, silver, and bronze loot. The code exposes methods like addGold, addSilver, addBronze, and getLoot, which update and report the accumulated treasure counts. The template renders a simple HTML page with a heading, but the interactive behavior occurs entirely in the browser console, where users can instantiate the object and call its methods to simulate collecting treasure. No external libraries or data sources are involved.
This example presents a "Dice Library" as a plain HTML page with a title and minimal styling, but all interaction occurs in the browser console. The code defines seven dice-rolling functions—`d2`, `d4`, `d6`, `d8`, `d10`, `d12`, and `d20`—each returning a random integer within its respective range. Each function uses a Fisher–Yates shuffle algorithm to randomly reorder an array of sequential numbers and then extracts the first element, adding one to yield a 1-based result. The functions are exposed via a module pattern, allowing console users to call them directly, such as `roll.d20()`, to simulate dice rolls without any visual output.
This example displays a responsive photo gallery from a fictional photographer, Jack Sparrow, with a grid of images that links to individual photo pages. The gallery uses the ReefJS library for rendering and a custom API module to fetch photo data. On each photo detail page, a cart feature stores selected items in the browser’s local storage via a cart helper, updating the interface to show whether an item has already been added.
Sparrow Photography displays a responsive grid of nature photographs, with each image linking to a detail page showing the photo's name, description, and price. The gallery uses the native Fetch API to retrieve photo data from an external JSON endpoint, while sessionStorage caches the response to avoid repeated network requests. JavaScript's URLSearchParams extracts the photo ID from the query string to render the correct item, and CSS Grid with media queries arranges the images across two to four columns depending on viewport width. The interface is built with plain JavaScript modules and semantic HTML, with no external visualization libraries.
This example displays a responsive photo gallery of sparrow images, with a listing page showing thumbnail grids and detail pages for individual photos. The code fetches photo data from the Vanilla JS Academy API and caches it in sessionStorage. JavaScript renders the grid using CSS Grid layouts that adapt across breakpoints, while a URL query parameter routes between the listing and item views. The implementation uses native `fetch`, `sessionStorage`, and template literals, with no external libraries.
Sparrow Photography is a simple, responsive photo gallery that displays a grid of images fetched from a remote API. The listing page uses a responsive CSS grid that adapts from two to four columns based on viewport width. Each photo is clickable and links to a detail page, where the selected image is shown with its title. Data is loaded asynchronously from a JSON API and cached in sessionStorage to speed up repeat visits. The gallery gracefully handles missing data or invalid photo IDs with a fallback message.
A web form with fields for name, address, email, and additional thoughts demonstrates an autosave feature that stores user input in the browser’s localStorage under the key `autosave_fields`. As the user types, the `input` event triggers serialization of the form data via `new FormData`, and after a one-second debounce, a status notification reading "Form data saved" appears and disappears after four seconds. On page load, the saved data is retrieved and repopulated into the fields. The implementation uses plain JavaScript with `localStorage.setItem`, `JSON.stringify`, and `setTimeout` for the animated feedback.
This example demonstrates a web form with autosave functionality for a single entry, showing how user input persists across page reloads. It displays fields for name, address, email, and additional thoughts, with data stored locally. The code uses the browser’s `localStorage` API and `JSON.parse`/`JSON.stringify` to save and retrieve form values on every input event. On page load, it repopulates fields from saved data; on submit, it clears the stored entry. The implementation relies on plain JavaScript with `querySelector`, event listeners, and the `for...in` loop to iterate over saved objects.
This example demonstrates a form that automatically saves user input to the browser’s localStorage as they type, allowing the data to persist across page reloads. The page presents fields for name, address, email, and additional thoughts, which are repopulated on load from stored values. It uses the Web Storage API’s `localStorage.getItem` and `localStorage.setItem` to retrieve and save each field’s value on the `input` event, and clears the saved data via `localStorage.removeItem` when the form is submitted. The second version stores all entries as a single JSON object using `JSON.parse` and `JSON.stringify`.
Monsters! Game is a single-page interactive memory game built with JavaScript and SVG icons. Players click on covered tiles to reveal hidden monsters, trying to find all 11 monsters without uncovering the sock that ends the game. The interface uses a simple three-column grid layout, and each tile toggles from a door image to a monster or sock icon. The game tracks clicks, reveals images by decoding base64-encoded data attributes, and displays a "Game Over" message when the sock is found, with an option to reload and play again.
Monsters! Game is an interactive memory game rendered as an SVG. Players click tiles to reveal hidden monster icons. The game uses a grid of clickable images, with each tile concealing a monster or a sock. The underlying code encodes the tile image data in base64 and decodes it on click to reveal the monster. Clicking on a sock triggers a "Game Over" message, while revealing all eleven monsters displays a congratulatory message. The visualization is built with a simple grid layout and SVG icons, with game logic handled by JavaScript event listeners.
Monsters! displays a shuffled grid of monster-themed SVG icons in a simple three-column layout. The page uses a JavaScript function to randomize the order of an array of monster images, then renders them as an HTML grid. Each monster is a distinct SVG icon, including one-eyed, multi-limbed, tentacled, and bug-like creatures, plus a single pair of socks as an odd one out. The project credits the individual icon designers in the footer. The rendering is done in SVG, and the layout is a responsive grid that scales images on smaller screens.
This example shows a magazine-style article feed titled “Dragon Trainer Monthly,” displaying fetched articles and author bios in a clean, single-column layout. It demonstrates client-side HTML sanitization to prevent cross-site scripting (XSS) attacks. The code uses the Fetch API with `Promise.all` to load article and author JSON data from two external URLs, then renders the content via `innerHTML` after passing it through a `cleanHTML` function that strips `<script>` tags and removes dangerous attributes like `on*` handlers and `javascript:` URLs.
Dragon Trainer Monthly displays a list of dragon-themed articles with titles, authors, author bios, article text, and publication dates. It fetches article and author data from two separate JSON endpoints via the Fetch API, merges them by matching author names, and renders the combined content as HTML into the page. The visualization uses async/await functions for data loading and template literals with a map method to generate the article markup. No charting or drawing libraries are used; the presentation relies on plain HTML and CSS.
Dragon Trainer Monthly fetches a JSON article feed from the vanillajsacademy.com API and renders each story as a static HTML card. The page displays article titles, authors, body text, and publication dates in a simple vertical list, using a template literal with a `map()` function to generate the markup. It relies on the browser’s native `fetch()` API and async/await syntax, with error handling that injects a fallback message into the DOM if the request fails. The visualization is text-focused, showing no charts or interactive graphics.
A web page displays Ron Swanson quotes, each paired with a looping GIF of the character. Clicking the "More Ron" button fetches a new quote from the Ron Swanson Quotes API and replaces the current text. The page uses the Fetch API and a custom function to track previously shown quotes in an array, preventing duplicates until 50 unique quotes have been displayed, after which the oldest quote is removed to allow new ones. The quote element uses `aria-live` for screen-reader updates.
This example displays a single Ron Swanson quote at a time, fetched from the ron-swanson-quotes.herokuapp.com API, with a button to load a new one. It shows how to avoid immediate duplicate quotes by storing recent quotes in an array; when a quote repeats, the app fetches again, and once 50 unique quotes are stored, the oldest is removed to make room. The code uses the Fetch API to request JSON data and updates the page’s blockquote element, while an `<img>` tag embeds a related GIF.
Random Ron displays a random Ron Swanson quote in a blockquote element on page load and whenever the user clicks the “More Ron” button. The page fetches quotes from the Ron Swanson Quotes API using the Fetch API, parsing the JSON response and inserting the text into the blockquote. It uses plain JavaScript with an event listener on the document to handle button clicks, and the initial quote is triggered programmatically by calling the button’s click method.
This interactive text editor displays live character and word counts as a user types. It shows the running totals in a sentence below the textarea, updating with each input event. The code uses the DOM API’s `querySelector` and `addEventListener` to bind an input listener, splitting the text on whitespace via a regular expression to count words, while character count is derived from the string’s `length` property. The page also includes ARIA live regions for screen-reader accessibility.
This example shows a live character and word counter for user-entered text. As the user types into a textarea, the page updates two counts in real time: the total number of characters and the number of words, calculated by splitting the input on spaces and filtering out empty strings. The visualization uses plain HTML, CSS, and vanilla JavaScript, with the `input` event listener on the textarea and the `querySelector` API to update the displayed counts. No external libraries or data sources are involved.
A textarea accepts user input and displays a live character count beneath it, updating as the user types or deletes. The page shows the current number of characters in bold, starting at zero when the field is empty. The code uses the browser’s native DOM `input` event and `event.target.matches()` to detect changes to the textarea, then updates the `#character-count` span’s text content via `document.querySelector()`. No external libraries are used; only plain JavaScript and HTML.
This example demonstrates a password visibility toggle across two separate forms: one for changing a username and another for changing a password. Each form contains a checkbox that, when checked, reveals its associated password fields as plain text. The page uses a single delegated click event listener on the document, which checks whether the clicked element matches either checkbox ID via `event.target.matches()`. It then traverses the DOM with `closest()` and `querySelectorAll()` to target only the password inputs within that form, switching their `type` attribute between `"password"` and `"text"` based on the checkbox state. The code uses vanilla JavaScript and standard HTML form elements, with no external libraries.
This example demonstrates a password change form with two separate password fields and a single "Show passwords" checkbox. The interface shows the current and new password inputs, with the checkbox toggling both fields between masked and visible text. The code uses plain JavaScript with the `querySelector` and `querySelectorAll` methods to access the checkbox and all password inputs, then listens for a `click` event to loop through each input and change its `type` attribute between `password` and `text`. No external libraries are used; the interaction relies entirely on native DOM manipulation and event handling.
This example demonstrates a login form with a “Show password” checkbox that toggles the visibility of the password field. When checked, the password input’s type attribute changes from “password” to “text,” revealing the typed characters; unchecking restores the masked state. The interaction uses vanilla JavaScript and the `addEventListener` method on the checkbox’s `change` event, with `setAttribute` to update the input type. The page is plain HTML and CSS, with no external libraries or data sources.
A visual study guide presents the topics and subtopics for the Microsoft 70-480 exam as an animated branching tree. The layout uses an SVG tree with nodes for each section, such as CSS and JavaScript, that expand into clickable leaves for individual concepts. Canvas rendering animates the tree’s growth, while D3’s force simulation positions the nodes. The guide’s content comes directly from a Markdown file, with each heading and bullet point mapped to a visual element.
This visualization shows how the composition of national diets has changed over time, using FAO data on kilocalories per person per day across ten commodity categories from 1961 to 2013. A small multiples grid of stacked area charts, one per country, animates through the years, with each category’s contribution to the total diet colored by a categorical scale. The animation highlights shifts in consumption patterns, such as the rise of oils and fats or declines in cereals. The charts are rendered in SVG with smooth transitions, and the color scheme is provided by d3-color.v1. Built with D3.js, the visualization lets viewers compare dietary trends across countries over time.
This interactive visualization uses stacked area charts to show how the composition of national diets—by commodity categories like cereals, pulses, meat, and dairy—changed annually from 1961 to 2013 for a selection of countries. The data comes from the FAO (2017) food supply dataset, with each stream colored via d3-color and rendered as animated SVG. As years advance, the proportional height of each category shifts, revealing long-term dietary transitions such as increasing meat consumption or declining reliance on cereals. The chart animates through time, allowing comparisons across countries and categories in kilocalories per person per day.
Four hundred colored circles wander randomly across a canvas, each assigned one of five warm hues by a D3 ordinal color scale. The animation runs on a `d3.timer`, updating each circle’s position by small random steps and redrawing them with Canvas 2D `arc` calls. The `globalCompositeOperation` set to `hard-light` blends overlapping shapes, creating shimmering color interactions. The data is procedurally generated in-browser, with random x/y coordinates, radii, and group assignments, and the rendering clears the canvas each frame before repainting.