Hey everyone! Are you excited about anything this beautiful Spring Friday? I am excited to be back to writing another tutorial after a month-long hiatus... and also excited to make it about one of my favorite video games of all time: Pokémon! As always, if you have an idea for a next topic, be sure to let me know in the comments!
"HTML-only, no JS!" ✨🪄
In previous tutorials, I focused more on design: I showed how to make a simple gradient picker, or a more flashy 3D extruded text art effect, all written in pure HTML and templating, leaving the JS heavy-lifting to the framework.
Today's tutorial takes a very different approach: It shows how you can quickly display public "web APIs" (that is, public data sets or web services) with just a few lines of code.
How to use the PokéAPI
This tutorial is 100% thanks to PokéAPI, which is a fun, fan-maintained database and API for retrieval of Pokémon franchise information and media. For example, this link provides info in JSON format for my favorite pink puff: https://pokeapi.co/api/v2/pokemon/jigglypuff
The final result
Try it out now, in less than 30 seconds: 🚀🚀🚀 Wanna skip ahead? Scroll to the end and copy the ~30 lines of HTML code into any local HTML file, and then open it in your browser. Modulo is a single-file framework with no dependencies and even runs embedded in local HTML files, so it's really that easy!
Starting with a basic H1 and StaticData
Let's start with something super basic: Let's get info from the API. We can start with <Template>
and <StaticData>
:
<Template>
<h1>{{ staticdata.name|capfirst }} Party!</h1>
</Template>
<StaticData
-src="https://pokeapi.co/api/v2/pokemon/jigglypuff"
></StaticData>
In this snippet, we have a very simple, one-line <Template>
that shows the name
property of the returned PokéAPI. We apply the |capfirst
filter to capitalize it (it is all-lowercase by default). The StaticData
supports JSON (among other formats) out of the box, which means all it needs is the URL to the API and it will integrate it into your component. If the StaticData
concept is giving you conceptual trouble, try this tutorial on integrating the GitHub API, or the play around with the interactive examples in Part 4 of the Modulo.js tutorial.
Looping through generations and the games
We have to write 2 for loops now: One for the generations, and one for the games.
How did I figure this out? I clicked through the results of the API, and deduced that .sprites
, and specifically .sprites.versions
has all the "generations" of games in the JSON Object data structure. This is where the data gets tricky, since it's not accessible "at the top level" (like .name
). We'll need to "drill down" to the right data.
So, nesting the two for-loops
, we get:
{% for generation, games in staticdata.sprites.versions %}
{% for game, images in games %}
Showing the front_default
image in the loop
Finally, we'll need to reference the front_default
image in an <img>
tag to display it. See below:
{% for generation, games in staticdata.sprites.versions %}
{% for game, images in games %}
<img src="{{ images.front_default }}" class="dancing-image" />
{% endfor %}
{% endfor %}
The {% for %}
loop repeats the HTML code contained within. This is how it "duplicates" the <img src="...">
over and over to show all the images. For more practice on {% for %}
loops, play around with the interactive examples in the documentation.
Adding the CSS animation
Finally, to wrap this up, we'll need to make 'em dance! I made a "PokeDance" animation, which rocks back and forth, notably making the transform-origin: bottom center
to make it look like their "center of gravity" is at the bottom (at their feet), as such:
.dancing-image {
transform-origin: bottom center;
animation: PokeDance 3s ease-in-out infinite alternate;
width: 200px;
}
@keyframes PokeDance {
20% { transform: rotate(15deg); }
40% { transform: rotate(-10deg); }
60% { transform: rotate(5deg); }
80% { transform: rotate(-5deg); }
100% { transform: rotate(10deg); }
}
<x-PokeParty>
- Embeddable snippet
Combining it all, and adding a few final tweaks (the title
on the image, and a tweak of adding -auto-isolate:=false
to prevent PokeDance
animation from being modified), we get the following:
<template Modulo>
<Component name="PokeParty">
<Template>
<h1>{{ staticdata.name|capfirst }} Party!</h1>
{% for generation, games in staticdata.sprites.versions %}
{% for game, images in games %}
<img class="dancing-image"
title="{{ generation }}: {{ game }}"
src="{{ images.front_default }}" />
{% endfor %}
{% endfor %}
</Template>
<StaticData
-src="https://pokeapi.co/api/v2/pokemon/bellsprout"
></StaticData>
<Style -auto-isolate:=false>
.dancing-image {
transform-origin: bottom center;
animation: PokeDance 3s ease-in-out infinite alternate;
width: 200px;
}
@keyframes PokeDance {
20% { transform: rotate(15deg); }
40% { transform: rotate(-10deg); }
60% { transform: rotate(5deg); }
80% { transform: rotate(-5deg); }
100% { transform: rotate(10deg); }
}
</Style>
</Component>
</template>
<script src="https://unpkg.com/mdu.js"></script>
<x-PokeParty></x-PokeParty>
Top comments (0)