• Minecraft

    Minecraft - Constructions entre amis

    Après avoir passé plusieurs soirées avec des amis à poser des blocs pour me divertir, passer du bon temps et poser des panneaux aléatoirement, j'en suis venu à regretter de ne jamais avoir gardé une trace de ces différents serveurs dans lesquels j'ai pu apporter ne serait-ce qu'une petite contribution créative et qui, a l'heure d'aujourd'hui n'existent peut-être plus.

    Les souvenirs de ces créations deviennent floues au fûr et à mesure que les années passent et je ne souhaite pas laisser la même chose arriver dans ce cas présent si tant est que ce blog survive à l'apocalypse qui nous attend tous de toute façon.

    Oublié le temple japonais relié par un long chemin à l'écart de la ville ou encore le réfrigérateur et la table dans une cuisine de taille démesurée. Nous voici maintenant sur un serveur qui n'a pas de nom spécifique (pour l'instant ?). Rejoint il y a peu, il a déjà subit nombre de changements.

    Capture d'écran du château de Puy du Ouf

    Le Puy du Ouf

    À mon arrivée, il était composé d'une seule petite ville "habitée". Le Puy du Ouf, comme son nom l'indique choque au premier abord par son château fort renfermant une petite dizaine de prisonniers marchands dont la seule utilité pour les personnages joueurs se résume à l'achat à bas prix d'équipements utilisés dans le cadre de quêtes de découvertes.

    Une gigantesque porte vers le Nether en fait un site touristique accessible pour qui traverser les dimensions ne représente aucun problème. S'ajoutant à cela, un port y est adossé afin de faciliter les déplacements fluviaux vers les différents endroits qui vous seront présentés dans cet article. Il est à noter la présence d'une genre de caravelle dont les amarres ne sauraient être larguées de sitôt.

    Le reste de la ville est composé d'un certain nombre d'habitations construites par les joueurs mais fondée sur une base pré-existante. On y trouve de nombreux villageois dans des corps de métier tout aussi variés s'affairant à leurs occupations quotidiennes. De temps à autres, zombies et autres monstres viennent perturber la tranquilité de la ville et défoncer quelques portes dans leurs poursuites meurtrières des joueurs.

    Capture d'écran de la vue d'une tour du chateau sur la ville de Puy du Ouf

    La découverte

    Le Puy du Ouf fut l'occasion de se familiariser avec ce monde hostile. Mais vint alors la lassitude et le besoin d'aventure. Il était temps de partir.

    Pour la première expédition, l'objectif fut d'aller découvrir l'ouest. Nous fûmes cependant coupé dans notre élan en arrivant à l'endroit d'où nous étions partis. Cocasse, l'antagonisme parfait de la découverte des amériques. Croyant découvrir de nouveaux territoires, nous avions seulement fait un joli tour.

    Tout ne fut pas vain pour autant, les deux nouveaux villages découverts sur la route furent immédiatement pillés, une pratique systématique questionnable, et nommés. Sunrise Valley, pour cette première bourgade de quelques maisons perdues entre deux montages qui ne nous a pas retenue plus longtemps. Et La Grande Motte sur Mer, un village près de la côte qui allait subir quelques changements.

    Mais la conquête de l'End n'attendit pas !

    Capture d'écran de la place principale de La Grande Motte sur Mer avec son totem et ses cloches

    À la conquête de l'End

    Revenu au Puy du Ouf et stuffé comme un cochon grâce aux marchands du château, le groupe de 5-6 joueurs passa la grande porte du Nether pour ensuite rejoindre, par un chemin protégé, la porte de l'End. Par une stratégie de groupe bien ficelée consistant à se poser individuellement sur les tours pour bolosser le dragon à coup de flêches, il fut facilement vaincu non sans quelques décès. RIP.

    La difficulté de la tâche résida principalement dans le fait d'éviter le regard des endermen qui pullulent dans l'End. Au moindre croisement, c'est la victimisation assurée. Seul l'eau peut vous protéger de ses êtres qui se téléportent à vos côtés instantanément pour vous asséner de fourbes petits coups.

    Mais là ne s'arrêta pas l'histoire, il est ensuite possible de se mettre à la recherche de cités de l'End, sortes de tours contenant des cadeaux, rien de bien glorieux. Après une longue errance entre les îles volantes dangereuses et les quelques petites cités quelques peu insignifiantes, le groupe revint sain et sauf téléportés par les Saintes Commandes admin. C'est chiant de revenir au portail du début - eh oh ça va hein !

    La Grande Motte sur Mer

    Ce fait héroïque accompli, les sessions suivantes furent consacrées quasi-exclusivement à re-dynamiser, pour ne pas dire gentrifier, l'endroit. Une ligne de chemin de fer relie désormais Le Puy du Ouf et la Grande Motte sur Mer. En majorité souterraine et aux virages très serrés dignes des meilleures attractions de Disneyland, c'est dire si ça secoue ! Cela reste supportable pour des enfants qui ne trouveront rien à redire bien évidemment. Attention à ne pas vomir son quatre heure.

    Capture d'écran d'un pont du chemin de fer reliant le Puy du Ouf à la Grande Motte sur Mer

    À l'arrivée dans la gare de la Grande Motte sur Mer, un distributeur de pastèques se trouve à disposition de celui qui cherche à étancher sa soif ou se rafraîchir. Les acteurs de la redynamisation jugèrent la nécessité de ce genre d'installation aussi importante que celle des fours communaux en libre-service, de l'élevage de mouton et de la chapelle dans les tons de la ville.

    Capture d'écran de la gare de la Grande Motte sur Mer de nuit

    Côté alimentation, la réhabilitation des productions agricoles de la ville eut un impact non négligeable. Les choix originaux d'exploiter des parcelles du versant de la grande motte menant à la partie supérieure du village n'avait sûrement pas été mûrement réfléchis et le terrain peu facile à cultiver de part sa nature a retrouvé son caractère naturel depuis.

    Non loin de là se tient dorénavant un grand escalier reliant les parties supérieures et inférieures. Grâce à cet ouvrage, les villageois ne se retrouvent plus dans l'obligation de devoir dévaler la colline pour se rendre en ville.

    Capture d'écran de l'escalier menant à la partie supérieur de la Grande Motte sur Mer

    Mais la vie n'est pas rose et la configuration peu protégée de la Grande Motte sur Mer conduit à une tragique extinction temporaire de la population locale, dommage colatéral des travaux qui durèrent de nombreux jours et nuits heure locale.

    Malgré une enquête poussée, rien n'avéra que les vagues de zombies et la relative proximité d'un mineshaft en aient été la cause. La piste d'une population relativement âgée et fortunée, venant passer ses derniers jours en bord de mer et se retrouvant à casser sa pipe, dans un intervalle de temps restreint, potentiellement dû au stress des travaux, ne fut pas exclue.

    Depuis, la Grande Motte sur Mer a retrouvée une population active. L'insécurité alimentaire des lieux, malgré la présence de diverses exploitations agricoles, poussent les villageois à systématiquement s'orienter dans une carrière de pêcheur.

    La ville côtière a donc retrouvé son caractère maritime d'antan mais la pression sociale reste forte et les différentes tentatives d'éviter le péché qu'est la conversion des prêtres en pêcheurs ont toutes échouées. La chapelle vide reste disponible pour quiconque voudrait venir y prêcher ses sermonts, mais gare au péché du pêcheur.

    Capture d'écran d'une exploitation agricole et de la chapelle de la Grande Motte sur Mer

    Village japonisant

    Le plan de relance de la Grande Motte sur Mer ainsi effectué, c'est sur un projet de village japonisant que se reporta la force de travail. D'abord par un temple composé d'un ascenseur téléporteur, d'un petit jardin et d'une source chaude. Puis par un château traditionnel inspiré de celui d'Osaka. Les travaux ne sont pas encore finis à la rédaction de cet article ni l'aspect village et le nom qui ne sont pas non plus déterminés.

    Capture d'écran du temple japonais du village

    Des outils pour pimenter le tout

    La communauté de Minecraft est très active. Entre les mods qui permettent l'optimisation, je pense notamment à Optifine qui doit être un des plus connus. Mais également aux shaders qui rajoutent un côté naturel. C'est d'ailleurs Sildur’s Vibrant Shaders qui est utilisé pour les captures d'écran de cet article.

    Il ne faut pas non plus oublier les outils autour du jeu comme Overviewer qui permet de générer une carte interactive. C'est quand même super cool de voir apparaître ses constructions et explorer les différents endroits que les joueurs ont découverts.

    Une carte interactive du serveur dans le navigateur web

    Voilà qui clôt un résumé de quelques petits mois de détente. On épargnera certains détails et les quelques bâtiments d'une taille démesurée qui sont également en construction sur la carte mais qui manquent encore de contexte pour figurer dans une rubrique spécifique. Loin de moi l'idée d'imposer un narratif qui pourra évoluer en fonction de chacun au fûr et à mesure des sessions. Si matière à développer se présente, cet article connaîtra peut-être une suite, qui sait.

    • Development

      Localizing your blog with Next 10

      Hey it's me again, with yet another blog post about Next!

      Back in June, I explained how and why I went from Gatsby to Next with my roughly crafted take on i18n. But time has passed and Next 10 came out with a small but efficient way of localizing your app. There are still a few things that aren't very clear at the moment but it's really promising.

      Configuration

      First of all, Next 10 introduces a new property called i18n where all the localization configuration is set to be.

      // next.config.js
      
      export default {
        i18n: {
          locales: ['en', 'en-GB', 'fr', 'br'],
          defaultLocale: 'en',
          localeDetection: false,
        },
      };
      

      Within this object, you have to specify the languages you want to enable alongside your default locale. You also get language detection and redirects for free if you're interested in such thing. I've disabled it since my case was a bit different, my blog's interface is only in English, but some articles aren't. I've decided to go that way out of convenience but in the future, I might reconsider translating the whole thing and enabling the detection.

      If you're interested in having a different domain per locale, it's also possible, check out the docs.

      Links

      So now, with this configuration settled, the subroutes for your blog are automatically generated so you might want to remove any custom route manipulation like:

      <Link href={'/' + (lang !== 'en' ? lang + '/' : '') + path}>
        <a>{lang}</a>
      </Link>
      
      // simply becomes
      <Link href={'/' + path} locale={l}>
        <a>{l}</a>
      </Link>
      

      Note: With Next 10, href changed and doesn't need to specify the route along the path with the prop as. The detection is now done automatically.*

      In my case, I also put a locale={false} on every Link that goes from a localized page to an english page like / or /about to opt-out of the automatic locale prefixing.

      Route generation

      As I said above, routes are automatically generated for every locales you declare. However, you can change that behavior within getStaticProps. As it automatically gets the default locale and the current locale, you can use the notFound option to disable the route as I did for my about page.

      export async function getStaticProps({ defaultLocale, locale }) {
        if (locale !== defaultLocale) {
          return {
            notFound: true,
          };
        }
      
        // ...
      }
      

      The same way, within getStaticPaths you can specify which locales you want to render for every path. I also chose to generate the english page for every article to keep consistency with the previous behavior I had. It redirects to the first locale found if it has no english version.

      Improvements needed

      The internationalization in Next just got its first version and we can expect some updates and features within the coming months. Automatic redirections from the explicit default locale's path (e.g. /en/my-article to /my-article) and the static export when localeDetection is disabled - or a client support of it - would be little things I'd like to see added and that has no workarounds for now.

      If you want to read more about the update, check out Next 10's official blog post.

      • Development

        Statically generated sitemap in Next.js >= 9.3

        When it comes to make a sitemap, Next doesn't want it to be as easy as making pages.

        A sitemap is just an XML file listing all your pages your website has, making it easier for search engines to find all the informations it needs without having to follow links here and there. You can also specify some data like changes frequency and priorities.

        First of all and before anything, do you really need a sitemap? I didn't but I like it, so I made it.

        Have you ever got sad seeing this screen being unable to make a good use of that data to make your sitemap?

        A screenshot of a Next build output

        So how can you make a sitemap with Next? People who got through this pain usually follow one of these 3 methods:

        Guerilla Sitemap

        Just write yourself the damn file and put it in the public folder.

        <?xml version="1.0" encoding="UTF-8"?>
        <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1" xmlns:xhtml="http://www.w3.org/1999/xhtml">
          <url>
            <loc>https://blog.yorunohikage.fr/</loc>
          </url>
          <url>
            <loc>https://blog.yorunohikage.fr/about</loc>
          </url>
        </urlset>
        

        Great but I don't have a 3 pages portfolio website.

        Dynamically rendered

        For you guys, you usually need to update your sitemap in real time as data is changed and updated indepentently from the builds. From there, you have two choices. Either you generate it from the /api folder like this:

        // pages/api/sitemap.xml.js
        
        export default (req, res) => {
          res.statusCode = 200;
          res.setHeader('Content-Type', 'application/xml;charset=utf-8');
        
          // grab the info you need...
        
          res.write(sitemap);
        
          res.end();
        };
        

        Or you can use a trick using getServerSideProps in a sitemap.xml.jsx file like this:

        // pages/sitemap.xml.jsx
        
        export const getServerSideProps = async ({ res }) => {
          res.statusCode = 200;
          res.setHeader('Content-Type', 'application/xml;charset=utf-8');
        
          // grab the info you need...
        
          res.write(sitemap);
        
          res.end();
        };
        
        // a component is needed
        export default () => null; 
        

        You can explore a bit more these solutions (with caching) in the articles Next.js 9.3 - generating a sitemap from dynamic content and Create a Dynamic Sitemap with Next.js.

        But I know this is not what you want.

        Either way, your file is not generated statically and if you're like, you know you can go f... yourself if you try to glob the filesystem on now.sh.

        So how can I render it statically during the build process?

        Observing what Vercel did, I took example from their very own Next.js website. They don't have any sitemap available (or I didn't see it) but they do have an RSS feed which would require pretty much the same process.

        What they apply is, they first hook into the webpack config within the next.config.js adding their script to the webpack entries list that gets processed:

        module.exports = {
          target: 'serverless',
          webpack(config, { dev, isServer }) {
            if (!dev && isServer) {
              const originalEntry = config.entry;
        
              config.entry = async () => {
                const entries = { ...(await originalEntry()) };
        
                // These scripts can import components from the app and use ES modules
                entries['./scripts/build-rss.js'] = './scripts/build-rss.js';
        
                return entries;
              };
            }
        
            return config;
          },
        },
        

        This builds it into ./next/serverless/scripts/build-rss.js along with all the things you need from your project code. Now, after the build step, they just execute the newly built script.

        Be careful, if your target is different, the folder will be different ! "server" is the default but now.sh enforce "serveless".

        So what's inside this script and how can we apply that to make a sitemap?

        // https://github.com/vercel/next-site/blob/master/scripts/build-rss.js
        
        // ...
        
        function importAll(r) {
          return r.keys().map(r);
        }
        
        const previewItems = importAll(require.context('../blog', false, /\-preview\.mdx$/));
        
        // ...
        
        function generate() {
          // ...
        
          fs.writeFileSync('./.next/static/feed.xml', rss);
        }
        
        generate();
        

        Every -preview.mdx files are imported and used to build this RSS feed that is finally written to the built folder.

        Applying the same principles, I made this:

        // scripts/generate-sitemap.js
        
        const fs = require('fs');
        const { SitemapStream, streamToPromise } = require('sitemap');
        
        // 1. Importing all the .jsx in the pages folder and keeping their paths
        function importAll(r) {
          return r.keys().map((key) => ({ path: key, module: r(key) }));
        }
        
        const pages = importAll(require.context('../pages', false, /.jsx$/));
        
        async function generateSitemap() {
          // 2. Creating a sitemap using a third-party package
          const smStream = new SitemapStream({
            hostname: 'https://blog.yorunohikage.fr',
          });
        
          await Promise.all(
            // 3. Looping through all the paths we found in pages folder
            pages.map(async ({ path, module }) => {
              // filename starting with _ are ignored
              if (/_[^/]+\.jsx/.test(path)) return;
        
              // has brackets -> find getStaticPaths or ignore
              if (/\[.+\]\.jsx/.test(path)) {
                const { getStaticPaths } = module;
        
                if (getStaticPaths) {
                  // getting all the statically generated paths
                  const { paths } = await getStaticPaths();
        
                  // replacing parameters in the dynamic path and writing it to the sitemap
                  paths.forEach(({ params }) => {
                    let pathToBuild = path.replace('./', '');
                    Object.entries(params).forEach(([key, value]) => {
                      const isSplat = Array.isArray(value);
                      pathToBuild = pathToBuild.replace(
                        `[${isSplat ? '...' : ''}${key}]`,
                        isSplat ? value.join('/') : value,
                      );
                    });
        
                    smStream.write({
                      url: pathToBuild.replace('index.jsx', '').replace('.jsx', ''),
                    });
                  });
                }
        
                return;
              }
        
              // just a normal static path
              smStream.write({
                url: path.replace('index.jsx', '').replace('.jsx', ''),
              });
            }),
          );
        
          smStream.end();
        
          const sitemap = await streamToPromise(smStream);
        
          // 4. Finally, you write everything in a file on the public folder
          fs.writeFileSync('public/sitemap.xml', sitemap);
        }
        
        generateSitemap();
        

        The most important part here, where the magic happens, is the loop. The data from all the getStaticPaths functions gets matched to the dynamic paths you found on your filesystem.

        This code is not made for hybrid websites, either you ignore the dynamically generated routes or you use one of the dynamically rendered method above.

        Just replace your build command with next build && node ./next/serverless/scripts/generate-sitemap.js on your script and you're good to go.

        Summary

        • Write your sitemap yourself if you only have a few pages, or don't even write one
        • If you need a dynamic sitemap from dynamic data, either use an /api endpoint or the getServerSideProps trick
        • Statically generating a sitemap is possible but it needs to be defined in a pre-built script before execution if you want to re-use your data-fetching logic
        • getStaticPaths can be used to get the generated data, then you just have to search/replace parameters within the routes and build the sitemap

        Final thoughts

        On a final note, you might want to subscribe to the GitHub issue : [Feature Request] native static sitemaps. Some day, we could get a true native way to hook into the static generated routes and ditch all these tricks for an easier and cleaner method. But for now, this suits my blog and I hope it did help you.

        • Development

        From Gatsby to Next but still static

        My last article was almost a year ago! I haven't given up, but as a true programmer, I've been doing more on the technical side than the actual content. If you can relate, you must be the type of people that is always unsatisfied with the tool and very slow when it comes to producing something with it. Anyway, in this case, I wanted this blog to be multilingual, since the first articles I wrote, back in 2012, were in French but I switched to English at some point. Also, I've been writing a few articles in Japanese to exercise more on the writing side and some of them might also fit in here.

        This blog has been powered by different engines throughout the years starting with Wordpress, moving to a simpler Jekyll static site and then Gatsby. And now I'm moving to Next. After working a bit with it, I concluded that it was so much easier to bend it towards what I needed. While Gatsby is nice when you don't do much outside the bounds, it can become cumbersome when you're expecting a bit more. The only downside I found to Next all those previous years was the path routes you had to specify in the config files to get a static site, I found it ugly. But in a recent update they introduce new methods to collocate the dynamic paths right with their page templates.

        The good

        So I started my Next project right in the Gatsby one, removing all those spread configs files down to just a few ones. Because I was using a pre-built template, I still had to keep some things like rucksack and lost grid. Maybe I'll get rid of those later. I got it working quickly without the articles. Then I headed onto the most important.

        Within the file [...slug].jsx which catches every path not predefined and the brand new getStaticPaths method, you can specify which dynamic paths you want to be rendered, that's where you have to query your filesystem to get the articles. With a few lines, you can get it working.

        // [...slug].jsx
        export async function getStaticPaths() {
          // getting all my articles
          const folders = glob.sync('articles/*/index.md');
          const slugs = [];
        
          for (let folderPath of folders) {
            // the directory's name will be the path
            const dirName = folderPath.split('/')[1];
        
            // we need to get the year, month, day and slug within the directory's name
            const splits = dirName.match(/(\d{4})-(\d{2})-(\d{2})-(.+)/);
            const arraySlug = splits ? splits.slice(1) : [slug];
        
            // let's save the slug
            slugs.push(arraySlug);
          }
        
          return {
            paths: slugs.map((slug) => ({
              params: { slug },
            })),
            fallback: false, // all other paths will go to 404
          };
        }
        

        What is great with that, it's the complete freedom on where the data comes from and which paths you want to generate. So if I change my data structure let's say to {year}/{month}/{day}/... instead later, I can come back, change a few lines and the result will be the same. Now that is working exactly as before. Let's add the internationalization now!

        // [...slug].jsx
        - const folders = glob.sync('articles/*/index.md');
        + const folders = glob.sync('articles/*');
        const slugs = [];
        
        for (let folderPath of folders) {
          // ...
        
        +   // finding languages (e.g. index.fr.md)
        +   const articlesPaths = glob.sync('index*.md', { cwd: folderPath });
        +
        +   // nothing? let's move on
        +   if (articlesPaths.length === 0) continue;
        +
        +   // pushing default lang path
        +   slugs.push(arraySlug);
        +
        +   // removing the default lang from the list
        +   if (articles.includes('index.md')) {
        +     articles.splice(articles.indexOf('index.md'), 1);
        +   }
        +
        +   // let's push the lang in the path (to get /{lang}/...)
        +   for (let article of articles) {
        +     const lang = article.match(/.*index\.(.+)\.md/)[1];
        +
        +     slugs.push([lang, ...arraySlug]);
        +   }
        
          // ...
        }
        

        So you get all the paths you need and if the article is not available in English, we'll have to redirect to the first locale we find.

        Getting the homepage list of articles with the other available languages is pretty much the same work since we need to find the alternatives but instead of just specifying the path, you load the content of said article within getStaticProps.

        // index.jsx
        export async function getStaticProps() {
          // ...
        
          for (let folderPath of folders) {
            // ...
        
            // importing the frontmatter and content
            const { data, content } = await import(`../articles/${dirName}/${filename}`));
        
            articles.push({
              ...data,
              slug,
              content,
            });
          }
        
          return {
            props: {
              articles,
            },
          };
        }
        

        You can also match the languages and add some data to the list, if you want to see how it's done you can look at the file on GitHub. I made it so all the article are displayed on the homepage but the language is specified if it's not English and alternative languages links are also available.

        The bad

        Before going on, let's just dig something, Markdown imports. Next is built on top of Webpack which can imports all sorts of files as long as you have something called a loader for it. Colocating the assets' articles and the article itself was something Gatsby plugins used to do, but I didn't find anything satisfying for Next and after taking example on the remark-loader, I've built my tiny loader based on the html-loader using the remarkable parser.

        const matter = require('gray-matter');
        const { Remarkable } = require('remarkable');
        const HTMLLoader = require('html-loader');
        const hljs = require('highlight.js');
        
        const md = new Remarkable();
        
        module.exports = function markdownLoader(content) {
          const callback = this.async();
        
          // let's parse the frontmatter
          const parsed = matter(content);
        
          // let's render the markdown and pass it to HTML loader
          const content = HTMLLoader(md.render(parsed.content));
        
          // exporting the module
          callback(
            null,
            `module.exports = {content: ${
              content.match(/(".+")/)[0]
            }, data: ${JSON.stringify(parsed.data)}};`
          );
        };
        

        It's not that good but it's working, I might come back to it later.

        The ugly

        The paths are generated and you also get the articles within the homepage but now we need to match the URL to the content. getStaticProps receives a parameter containing params which is what we specified in getStaticPaths.

        export async function getStaticProps({ params }) {
          const { slug } = params;
        
          // finding lang and article path within the slug parameter
        
          // getting article paths...
        
          // The lang is the default but we don't have it, we need to redirect to the first one we find
          if (lang === 'en' && !articles.includes('index.md')) {
            const redirectToLang = articles[0].match(/index\.(.+)\.md/)[1];
            return { props: { redirectToLang, path } };
          }
        
          // importing asked article and matching other langs...
        }
        

        We can use the parameter to do our loading strategy (nothing new here) but we need to specify the need for redirection when English is not available (that will support old URLs). Just use the props within the component:

        import Head from 'next/head';
        import { useRouter } from 'next/router';
        
        export default function Article({ path, redirectToLang }) {
          const { replace } = useRouter();
        
          if (redirectToLang) {
            if (typeof window !== 'undefined') replace(`/${redirectToLang}/${path}`);
        
            // if JS is disabled, I guess that's the only way to redirect within a static website
            // and without HTTP redirects of course
            return (
              <Head>
                <meta httpEquiv="refresh" href={`0;url=/${redirectToLang}/${path}`} />
              </Head>
            );
          }
        
          // returning formatted article
        }
        

        Now.sh

        Finally, I used to host the blog on Netlify (which is great) but Now is made my the same people making Next and the project doesn't have to be exported to a static website to work on it even though it could. It is just statically optimized at build time.

        And that's it! I moved my blog to Next and it's multilingual! You can check this article's French version by clicking the FR link or button on top of the article.

        • Music

        5 Japanese Pop / Punk bands you might wanna know about

        Two years ago, I wrote a blog post about 5 French Pop / Punk bands you might wanna know about and as crazy at it seems, it has been so far my most viewed article on my blog. As my interest from punk & co grew more and more since that time, I wanted to give a shoutout to more bands I've discovered but from Japan this time. Unlike France with either hardcore or indie-psych-post-proto-experimental music, Japan seems to have a huge straightforward pop independent scene that is matching my taste perfectly.

        SpecialThanks

        Pop punk from Nagoya. Started in 2005. Abbreviated as スぺサン.
        Energetic and very catchy band lead by guitarist and (awesome) vocalist Misaki since its beginning. She's currently the only one remaining in the band touring with support members while looking for musicians to join the band. Let's hope she can find members again, their music is so good it would be a shame we don't get more of it. They use to sing exclusively in English but on the last records it's mainly Japanese.

        Yabai T-shirts Yasan (ヤバイTシャツ屋さん)

        Pop punk / Melodic hardcore from Osaka. Started in 2012. Abbreviated as ヤバT.

        "3 piece girl's technopop unit targeting 50 years old women" according to the band's website. This silly band is full of humor. The name itself could be translated as Crazy T-shirts Store. Their lyrics are often describing crazy stuff and using bad puns. For example Happy Wedding Mae Song wishes happiness for a couple hurrying to get married but including things like "you might break up and divorce within 2 years but happy marriage". They mainly sing in Japanese.

        LONGMAN

        Melodic punk from Ehime. Started in 2012.

        Sometimes emotional but often fast and very melodic punk, they also use skank riffs and ska sounds for the best. When I discovered them, they weren't really making a lot of views on YouTube but they got quite popular quickly. I wouldn't say it's a mainstream band now but it's growing fast and they are taking part in a lot of festivals now. They sing in English but often mix it with Japanese.

        ELLEGARDEN

        Pop punk from Chiba. Started in 1998. Abbreviated as エルレ.

        If you only listen to their English songs, you won't notice this is a japanese band. Or maybe, I don't know, I'm not a native English speaker but my point is the English pronunciation of the singer is perfect. They have this Simple Plan-like melodies but also deeper Weezer-like songs. They chose to take a break in 2008 to focus on other projects they had but decided to reunite 10 years later. At the moment, no records is planned but they are touring in some festivals. You might just want to hope.

        Hi-STANDARD

        Punk / Hardcore from Osaka. Started in 1991. Abbreviated as ハイスタ.

        Slightly hardcore sometimes, almost always punk, definitely poppier now (if that's a word), it's quite an old band but they definitely deserve your attention. They last released "The Gift", a song from the eponym album they printed on a Shibuya station wall in Tokyo before releasing the actual song, so people could play it before. They mainly sing in English.

        • Reading
        • Language

          The 54 characters short stories challenge

          It's been a while I was looking for material to improve my Japanese, getting to know more kanji, knowing words and expressions. I've been trying to read the short news on the NHK easy website, but I wasn't really into it. Since the content is changing almost every day, you don't see any form of progress or rewards.

          But these days I've been in Paris for work and decided to stop by the Japanese bookshop there, it was literally 15 minutes away from the workplace. It's quite a big place, with two floors, comparing to what you can find in Lyon... nothing. So I just went there straight after work to take a look and stumbled across the easy-to-read and recommended book section. And there was this book, called the 「54字の物語」, literally "Stories in 54 characters". The lady told me the required kanji level for this was similar to what primary school students knows in Japan and on each page, you get a simple explanation of the previous page's short text. So I decided to give it a shot.

          Cover of 54字の物語 © @ujiqn

          To spice things up, and since there is 90 stories, I thought it could be cool to challenge myself to read one per day. But, to be sure everything was understood and to keep on doing it, I had to write the translation down somewhere. You know how it is easy to just let something go and forget about it. I had no intention in ruining the book by writing on it. I didn't think it would either fit a blog post, so I went with Instagram stories instead. It seemed like a good place: picture, to show the original story, text, to write the translation on it and also a pin functionality on the profile, to keep them in one place, separated from the other random stuff I can share. Nice!

          So here you go, I currently read and "translated" half of the book you can now watch here:

          🎉 The stories in 54 characters challenge on Instagram. 🎉

          Along the way, I noticed a few things that made this book even more interesting. A lot of stories are made according to a pattern: a normal situation is described followed by a pun or a weird element that completely change the understanding of the situation. For example, in the first pages, there's a funny story that made me laugh:

          海外旅行の大事な場面で、パパがくれた辞書に何度も助けられたよ。でもトイレに紙がない国にはもう行きたくないな。 "During important moments of my trip abroad, the dictionary my father gave me saved me many times ! But, I don't want to go in countries without toilet paper in the restroom anymore." If you didn't understand the joke, the guy probably had to use his dictionary to wipe himself, just saying.

          In an even more creative way, I found a story that is sort of an Easter egg. In Japan, unlike France, a lot of books have a dust cover and, sometimes, even a promotional belly-band, called obi coming from the Japanese kanji 帯. These are usually better crafted than the underlying cover. The paper is often soft or shiny and colorful, unlike the simple and monochrome cover it protects. And a lot of manga I've been reading often hide small drawings there, like funny cartoons related or not to the story you can find inside. K-ON!, for example, had these silly 4-cases short stories, Fullmetal Alchemist had one black cartoon per pure white cover... This has also inspired foreign drawers to make their own, French manga-like Lastman for example. It has this sex scene (nothing graphical) under the dust cover with the main character saying "what are you looking at?". It makes the undercover a private place where things shouldn't be seen but you'd still want to peek in. It can also be kind of a tool to hide what wouldn't have been accepted in a library or simply random thoughts and sketches not matching the content.

          When I removed the dust cover to see what's inside — note that I've been so used to these, it's almost a mechanical thing to do when I buy a book with a dust cover now — I found a short story, how surprising... But I didn't immediately notice it was a different story from the one on the dust cover, the latter being just a retake from the book. So when I read it, I'd wanted to clap the author for such a clever note.

          Belly-band and dust cover next to the gray cover showing a short story: こんなところまで読んでくれてありがとう。嬉しいよ。だけど、少し肌寒いからそのカバーはかけておいてくれないか? Undercover story: Thanks for reading this far. I'm happy! But, as it is a bit cold, could you put back the cover?

          This simple short story reflects the humor the entire book is made of and this comparison with the cover of the book being wore to stay warm is brilliant I think. Congrats! 👏

          I encountered another story type as well in a way they use the language itself to play with it. I remember one story where a thief stole a plate, plate whose writing was also included in the steal character, but as it was stolen, it changed the meaning of the story. I don't remember if this was the first case of "writing play" I had seen but it sure is very clever. Either be meaning, writing or pronunciation tricks, this book has a lot to offer.


          At the end of the book, the author explains a few things to make your own stories as well and share them on social networks. I might want to try writing my own stories later on, we'll see if I feel like it.

          I also thought about it since the beginning, but I'm following and supporting Dogen's awesome lessons on Patreon about Japanese pitch-accent patterns and phonetics, and it could be nice to try recording myself pronouncing these short sentences as a way to practice.

          If you understand Japanese, I encourage you to see the author's other works, it is really interesting and I love his website: thinking.co.jp

          While writing this article, I came across the announcement of the second volume, chills special, now available. Take a look at it! I'll definitely buy it some day and might do this challenge myself one more time.

          See you!

          Making a Twitter emoji map with Yahoo Weather API

            Parametric font workshop in Darmstadt

              Migrating 40k users from Hoodie / CouchDB to Graphcool

                Nichijō - 日常

                  5 French Pop / Punk bands you might wanna know about

                    Setting up a React Native & Web project

                      REST API made easy with Apex, AWS Lambda and AWS API Gateway

                        The Renewal

                          Inserting React components inside your Jekyll markdown posts

                            Thoughts about relationship deletion in Redux with Normalizr

                              Forms without refs in React stateless components

                                Echofon for Firefox : The renewal

                                  Pretty printing all JSON output in Silex PHP

                                    [fr] Symfony2 : Protéger ses entités avec les voters

                                      [fr] Global Game Jam 2015 - Que ferait MacGyver ?

                                        [fr] SuperTurkey - Thanksgiving

                                          [fr] Ménage de prin... automne

                                            [fr] Informations ISEN CIR3 - L'alternance en Cycle Informatique & Réseaux

                                              [fr] Angel Beats! - エンジェルビーツ!

                                                [fr] The Internet's Own Boy : The Story of Aaron Swartz

                                                  [fr] Glass Camp Bank à Brest

                                                    [fr] Le Trailer de Brezeliad ou Le Parcours du Combattant

                                                      [fr] Brezeliad - Première séquence gameplay

                                                        [fr] Une patate volante sur Twitter

                                                          [fr] Stunfest J-27 - L'aventure continue

                                                            [fr] L'offre légale chez EA

                                                              [fr] Stunfest - J-100

                                                                [fr] Marty - Back To The Future

                                                                  [fr] Steins;Gate - シュタインズ ゲート

                                                                    [fr] Enfin un nom de domaine !

                                                                      [fr] OnHack Reborn !

                                                                        [fr] Une deuxième année bien chargée

                                                                          [fr] Raspberry Pi - Un ordinateur low-cost au goût de framboise

                                                                            [fr] Echofon for Firefox (Twitterfox) is not dead (et espérons qu'elle le restera)

                                                                              [fr] Groar ou l'art de ne jamais finir ses projets

                                                                                [fr] Extensions Gnome-Shell - Requêtes HTTP avec libsoup

                                                                                  [fr] Gérer les changements de maps avec MelonJS

                                                                                    [fr] Les Mystères de Rennes

                                                                                      [fr] Global Game Jam 2013 - Retour d'expérience

                                                                                        [fr] Les Enfants Loups, Ame et Yuki - おおかみこどもの雨と雪

                                                                                          [fr] Puella Magi Madoka Magica - 魔法少女まどか☆マギカ

                                                                                            [fr] Accel World - アクセル・ワールド

                                                                                              [fr] Saleté de système de traduction !

                                                                                                [fr] Et encore un blog !