# \[Userscript\] Jitai v2

**URL:** <https://community.wanikani.com/t/userscript-jitai-v2/61145>\
**Category:** API And Third-Party Apps\
**Created:** [March 28, 2023, 10:27am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145 "2023-03-28T10:27:26Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![rogerxiii](https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/wanikanicommunity/original/3X/f/d/fd4c154120954695f788402f3bcf4e616499bc2d.png) [@rogerxiii](https://community.wanikani.com/u/rogerxiii)\
**Post date:** [March 28, 2023, 10:27am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/1 "2023-03-28T10:27:26Z")

</div>

Since the new WaniKani UI update [this Jitai script](https://community.wanikani.com/t/jitai-%E5%AD%97%E4%BD%93-the-font-randomizer-that-fits/12617) is broken. I quickly completely rewrote the logic to make it work with the current version, see code below.

I will provide minimum to no support or help, I just thought it’d be nice to share a quick solution for those that need it.

```auto
// ==UserScript==
// @name Jitai
// @version 2.0
// @description Display WaniKani reviews in randomized fonts, for more varied reading training.
// @author rogerxiii (original by obskyr)
// @license MIT
// @icon http://i.imgur.com/qyuR9bD.png
// @include /^https?://(www\.)?wanikani\.com/subjects/review/?$/
// @grant none
// ==/UserScript==

/*
    To control which fonts to choose from, edit this list.
    If you feel too many fonts of a certain type are showing
    up, remove a few of those from the list. If you've got
    fonts that aren't in the list that you'd like to be used,
    add their names and they'll be in the rotation.
*/

var fonts = [
    // Default Windows fonts
    "Meiryo, メイリオ",
    "MS PGothic, ＭＳ Ｐゴシック, MS Gothic, ＭＳ ゴック",
    "MS PMincho, ＭＳ Ｐ明朝, MS Mincho, ＭＳ 明朝",
    "Yu Gothic, YuGothic",
    "Yu Mincho, YuMincho",

    // Default OS X fonts
    "Hiragino Kaku Gothic Pro, ヒラギノ角ゴ Pro W3",
    "Hiragino Maru Gothic Pro, ヒラギノ丸ゴ Pro W3",
    "Hiragino Mincho Pro, ヒラギノ明朝 Pro W3",

    // Common Linux fonts
    "Takao Gothic, TakaoGothic",
    "Takao Mincho, TakaoMincho",
    "Sazanami Gothic",
    "Sazanami Mincho",
    "Kochi Gothic",
    "Kochi Mincho",
    "Dejima Mincho",
    "Ume Gothic",
    "Ume Mincho",

    // Other Japanese fonts people use.
    // You might want to try some of these!
    "EPSON 行書体Ｍ",
    "EPSON 正楷書体Ｍ",
    "EPSON 教科書体Ｍ",
    "EPSON 太明朝体Ｂ",
    "EPSON 太行書体Ｂ",
    "EPSON 丸ゴシック体Ｍ",
    "cinecaption",
    "nagayama_kai",
    "A-OTF Shin Maru Go Pro",
    "Hosofuwafont",
    "ChihayaGothic",
    "'chifont+', chifont",
    "darts font",
    "santyoume-font",
    "FC-Flower",
    "ArmedBanana", // This one is completely absurd. I recommend it.
    "HakusyuKaisyoExtraBold_kk",
    "aoyagireisyosimo2, AoyagiKouzanFont2OTF",
    "aquafont",

    // Add your fonts here!
    "Fake font name that you can change",
    "Another fake font name",
    "Just add them like this!",
    "Quotes around the name, comma after."
];

var existingFonts = [];
for (var i = 0; i < fonts.length; ++i)
{
    const fontName = fonts[i];
    if (fontExists(fontName)) existingFonts.push(fontName);
}

function fontExists(fontName) {
    // Approach from kirupa.com/html5/detect_whether_font_is_installed.htm - thanks!
    // Will return false for the browser's default monospace font, sadly.
    var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    var text = "wim-—l~ツ亻".repeat(100); // Characters with widths that often vary between fonts.

    context.font = "72px monospace";
    var defaultWidth = context.measureText(text).width;

    // Microsoft Edge raises an error when a context's font is set to a string
    // containing certain special characters... so that needs to be handled.
    try {
        context.font = "72px " + fontName + ", monospace";
    } catch (e) {
        return false;
    }
    var testWidth = context.measureText(text).width;

    return testWidth != defaultWidth;
}

function isCanvasBlank(canvas) {
    return !canvas.getContext('2d')
        .getImageData(0, 0, canvas.width, canvas.height).data
        .some(channel => channel !== 0);
}

function canRepresentGlyphs(fontName, glyphs) {
    var canvas = document.createElement('canvas');
    canvas.width = 50;
    canvas.height = 50;
    var context = canvas.getContext("2d");
    context.textBaseline = 'top';

    context.font = "24px " + fontName;

    var result = true;
    for (var i = 0; i < glyphs.length; i++) {
        context.fillText(glyphs[i], 0, 0);
        if (isCanvasBlank(canvas)) {
            result = false;
            break;
        }
        context.clearRect(0, 0, canvas.width, canvas.height);
    }

    return result;
}

// -----------------------------------------------------------------------------------------------------

const ele = document.getElementsByClassName("character-header__characters")[0];
const default_font = getComputedStyle(ele).fontFamily;
let current_font = default_font;

let style = document.createElement("style");
style.appendChild(document.createTextNode(".character-header__characters:hover { font-family: var(--font-family-japanese-hover); }"));
ele.style.setProperty("--font-family-japanese-hover", current_font);
document.head.appendChild(style);

// On Submit
window.addEventListener("didAnswerQuestion", function()
{
    ele.style.setProperty("--font-family-japanese", default_font);
    ele.style.setProperty("--font-family-japanese-hover", current_font);
});

// On Next
window.addEventListener("willShowNextQuestion", function(event)
{
    const characters = event.detail.subject.characters;
    if (typeof(characters) == "string")
    {
        do current_font = existingFonts[Math.floor(Math.random() * existingFonts.length)];
        while (!canRepresentGlyphs(current_font, characters));

        ele.style.setProperty("--font-family-japanese", current_font);
        ele.style.setProperty("--font-family-japanese-hover", default_font);
    }
});

```

---

<div class="post-metadata">

**Author:** ![fallynleaf](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/fallynleaf/32/393300_2.png) [@fallynleaf](https://community.wanikani.com/u/fallynleaf)\
**Post date:** [March 28, 2023, 11:37am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/2 "2023-03-28T11:37:07Z")

</div>

Thank you so much! This is fantastic!

---

<div class="post-metadata">

**Author:** ![Sulax](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/sulax/32/190013_2.png) [@Sulax](https://community.wanikani.com/u/Sulax)\
**Post date:** [March 29, 2023, 3:55pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/3 "2023-03-29T15:55:01Z")

</div>

Thanks. I.will try it later 🙂

---

<div class="post-metadata">

**Author:** ![JuiceS](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/juices/32/371203_2.png) [@JuiceS](https://community.wanikani.com/u/JuiceS)\
**Post date:** [March 31, 2023, 8:24am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/4 "2023-03-31T08:24:30Z")

</div>

Thanks a lot rewriting the script. 🙂  
I think in the old one there was something to prevent a font being used when a character wasn’t covered by it. Do you happen to know which part that was? I’m really not that experienced with coding.

---

<div class="post-metadata">

**Author:** ![rogerxiii](https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/wanikanicommunity/original/3X/f/d/fd4c154120954695f788402f3bcf4e616499bc2d.png) [@rogerxiii](https://community.wanikani.com/u/rogerxiii)\
**Post date:** [March 31, 2023, 8:41am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/5 "2023-03-31T08:41:22Z")

</div>

I copied that logic from the previous script, so it should be identical!  
If you want to look at the code you can see the function _canRepresentGlyphs_ does that.

---

<div class="post-metadata">

**Author:** ![DasHannes](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/dashannes/32/313108_2.png) [@DasHannes](https://community.wanikani.com/u/DasHannes)\
**Post date:** [April 1, 2023, 5:08pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/6 "2023-04-01T17:08:31Z")

</div>

Great work. I had a custom addition, do you have a quick solution how to integrate that, too? I used the KanjiStrokeOrders font from another script to show stroke orders on CTRL key down:

> Blockquote  
> init: function() {  
> jitai.$characterSpan.css(‘font-family’, ‘KanjiStrokeOrders’);});  
> jitai.$characterSpan.css(‘font-family’, ‘Ackaisyo’);});

```
    //CTRL keydown sets to default font
    $(document).keydown(function(event) {
        console.log(event.which);
        if(event.which === 17) {
            jitai.$characterSpan.css('font-family', 'KanjiStrokeOrders');
        }
    });
    //CTRL keyup sets to random font again
    $(document).keyup(function(event) {
        console.log(event.which);
        if(event.which === 17) {
            jitai.$characterSpan.css('font-family', 'Ackaisyo');
        }
    });

```

---

<div class="post-metadata">

**Author:** ![MaraVos](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/maravos/32/443784_2.png) [@MaraVos](https://community.wanikani.com/u/MaraVos)\
**Post date:** [April 18, 2023, 2:57pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/7 "2023-04-18T14:57:47Z")

</div>

Hi, sorry, but could someone explain how to implement this fix? Do I just go in and completely replace the old code with the new code? Thanks in advance. 🙏

---

<div class="post-metadata">

**Author:** ![rogerxiii](https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/wanikanicommunity/original/3X/f/d/fd4c154120954695f788402f3bcf4e616499bc2d.png) [@rogerxiii](https://community.wanikani.com/u/rogerxiii)\
**Post date:** [April 19, 2023, 8:41am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/8 "2023-04-19T08:41:07Z")

</div>

Indeed, copy that whole code to either a new script or replace the old one!

---

<div class="post-metadata">

**Author:** ![MaraVos](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/maravos/32/443784_2.png) [@MaraVos](https://community.wanikani.com/u/MaraVos)\
**Post date:** [April 19, 2023, 1:12pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/9 "2023-04-19T13:12:52Z")

</div>

Thanks so much! Looks like it’s working! 😁

---

<div class="post-metadata">

**Author:** ![luxluxlux](https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/wanikanicommunity/original/3X/f/d/fd4c154120954695f788402f3bcf4e616499bc2d.png) [@luxluxlux](https://community.wanikani.com/u/luxluxlux)\
**Post date:** [April 21, 2023, 3:04pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/10 "2023-04-21T15:04:17Z")

</div>

you’re a hero, thank you!

---

<div class="post-metadata">

**Author:** ![DasHannes](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/dashannes/32/313108_2.png) [@DasHannes](https://community.wanikani.com/u/DasHannes)\
**Post date:** [April 23, 2023, 9:43pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/11 "2023-04-23T21:43:37Z")

</div>

This version crashes my reviews, looks like every time a ~ item comes up:  
~匹  
~毎に  
~宅

Loading these reviews freezes and timeouts my tab. Any ideas why?

---

<div class="post-metadata">

**Author:** ![rogerxiii](https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/wanikanicommunity/original/3X/f/d/fd4c154120954695f788402f3bcf4e616499bc2d.png) [@rogerxiii](https://community.wanikani.com/u/rogerxiii)\
**Post date:** [April 26, 2023, 8:29am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/12 "2023-04-26T08:29:20Z")

</div>

I just had one in my reviews today and it worked fine. If you have other scripts running then one of them might be interfering, you could try turning some off and see which causes the crash.  
Alternatively, when it happens again please show me what error shows up in the console.

As a side question, do you have enough fonts installed? I think there’s a bug that I haven’t fixed yet for when there’s no installed fonts available for an item, it doesn’t default back to the normal wanikani font. That could be your issue as well.

---

<div class="post-metadata">

**Author:** ![Jrom](https://cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/wanikanicommunity/original/3X/f/d/fd4c154120954695f788402f3bcf4e616499bc2d.png) [@Jrom](https://community.wanikani.com/u/Jrom)\
**Post date:** [April 28, 2023, 2:22am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/13 "2023-04-28T02:22:32Z")

</div>

I don’t know if this is due to my slow internet connection, but it only applies the styling after a second for the very first item to be reviewed. Is the event `"willShowNextQuestion"` released only after a delay? If so, wouldn’t it be better to set `current_font` to a starting random font and then replace the `do while` block with a `while` one?

---

<div class="post-metadata">

**Author:** ![marciska](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/marciska/32/5585_2.png) [@marciska](https://community.wanikani.com/u/marciska)\
**Post date:** [April 29, 2023, 8:13am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/14 "2023-04-29T08:13:04Z")

</div>

I posted an update on Jitai over on the original thread.

> [@Jitai (字体): The font randomizer that fits](https://community.wanikani.com/t/jitai-%E5%AD%97%E4%BD%93-the-font-randomizer-that-fits/12617/675):
>
> Sorry for being late on this. Submitted my dissertation and finally had the time to work on fixing the script. Many thanks to @rogerxiii who provided a quick fix in the meantime! [Jitai v3](https://raw.githubusercontent.com/marciska/Jitai/main/Jitai.user.js) I decided to completely rewrite the entire script. Jitai is probably my most favorite script, so it’s sad to see that it is not anymore maintained by the original creator. Even before the recent WK update it wasn’t bug-free, and adding/removing fonts was ugly. You had to edit the script, but then you couldn’t…

---

<div class="post-metadata">

**Author:** ![drewbob01](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/drewbob01/32/251758_2.png) [@drewbob01](https://community.wanikani.com/u/drewbob01)\
**Post date:** [December 9, 2023, 4:36am UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/15 "2023-12-09T04:36:39Z")

</div>

This is champion status. Used Jitai back in the day before I reset, and was really bummed to see it wasn’t working now that I’m going through WK again. Thank you for reviving such a useful tool!

---

<div class="post-metadata">

**Author:** ![BlueRaja](https://sea1.discourse-cdn.com/wanikanicommunity/user_avatar/community.wanikani.com/blueraja/32/5350_2.png) [@BlueRaja](https://community.wanikani.com/u/BlueRaja)\
**Post date:** [February 14, 2024, 9:55pm UTC](https://community.wanikani.com/t/userscript-jitai-v2/61145/16 "2024-02-14T21:55:00Z")

</div>

The font update today broke this ☹

Someone posted a fix [here](https://community.wanikani.com/t/jitai-%E5%AD%97%E4%BD%93-the-font-randomizer-that-fits/12617/718)
