Leone Huang's Projects
Leone Huang (online nickname 'JaPNaA') has been programming by passion since middle school, accumulating over 8 years of programming experience and developed over a hundred projects.
This page serves as a ad-hoc showcase of some of the larger projects Leone has worked on. (Leone has a showcase of all the projects on gh.japnaa.dev, but the website was designed not with professional intent. A redesign is in progress.)
FlowEditor
FlowEditor is Leone's most recent project. This is a solo project -- Leone designed the UI, UX, setup the tech stack, and wrote all the code.
Flow Editor is a visual instruction editor. The image below is a screenshot of the FlowEditor with the visual novel plugin, and a sample of a comedy story (taken way out of context).
Purpose
FlowEditor was created to simplify the creation of 'flows' or in-game scripts, including dialog and code execution.
Leone realized plain code was unsuitable for in-game scripts. In-game scripts are often long, linear, and more difficult to unnecessarily difficult to navigate, test, and manage.
The FlowEditor makes such management, connecting, and writing of scripts visual and more efficient.
Image: FlowEditor allows zooming out to get a full view of the script's structure.
FlowEditor is becomes IDE for in-game scripting -- allowing scripters to write, view, and test their scripts in the same application. Additionally, scripts have access to a 'time machine' that allows them to save and restore the execution of the flow. The application includes support for additional media such as images, animations, and audio.
Technical Challenges
The biggest challenge for this project is accepting text input from the user. One may think this is a simple task, however, when adding touch keyboards and alternative input methods for CJK (Chinese Japanese Korean), the browser does not provide adequate APIs to facilitate automatically-formatted and structured text input.
Let's consider the possible methods to accept text input from the user.
Capture key presses directly and emulate a text editor. (addEventListener("keydown", ...))
This is the most naive approach, but could not support touch keyboards (especially with autocorrect) nor IMEs (input method for CJK charactesr). Having used desktop applications with a mobile keyboard, not having autocorrect is fatal to productivity on the small screen. Thus, this option was ruled out.
Use an invisible textarea
We can create an html <textarea> element and keep the user's cursor focused on the textarea.
This is the approach taken by Electron code editors such as Microsoft's VSCode and (formerly) Github's Atom. This approach only adds support for IMEs, but does not support autocorrect for touch keyboards. Additionally, since the cursor is inside an invisible textarea, we have to position this cursor ourselves.
We can solve autocorrect by altering the invisible textarea method -- specifically, not clearing (textarea.value = "") on every input event. Instead, on every input event, we can then compare the old textarea value and the new textarea and apply the changes to the actual data.
However, we run into a different fatal problems using this method on mobile.
On Android, a user can move the cursor by dragging left and right on the spacebar. It turns out Chrome does not send any JavaScript events, so we cannot reflect the cursor movement in the invisible textarea visually. We can work around this by polling the position of the cursor every frame, which would be fairly inexpensive.
We can't move the cursor to reflect changes when the user selects text, since moving the cursor would remove the selection!
In attempt to fix these issues, I had to consider an alternative.
Use a visible textarea
We can fix the visual issues by overlaying the textarea over the visual text. We need to ensure that the textarea and the visual text have the exact same spacing and size, otherwise the textarea's (now visible) cursor can be placed in the right position on the text.
Unfortunately, this is not possible. The browser has different logic to break lines for regular text and text in textareas. Different logic to break lines means the cursor is sometimes placed incorrect, which is incredibly confusing for the user, thus, this option is also not possible.
Use contenteditable
Contenteditable would fix all problems with visuals. The only issue is the complexity of parsing contenteditable input. There is no (standard) API to extract the text inputted into a contenteditable element.
This means we must attach a MutationObserver to the contenteditable element, parse each change in element, and then dispatch those as events the rest of the system understands (such as "change the text in this area", "remove this line", or "insert a line", or, all of those at the same time, since a user can also paste text!).
contenteditable is the most complex option, however, is the only viable option to ensure the best experience for FlowEditor users.
There are still some workarounds for IME input, however, other applications such as StackEdit and Google Chrome's DevTools that contentediatble must make same compromises.
The second biggest challenge is the compilation and execution of the flow instructions. We must take the boxes and graph the user creates and turn that into executable code. The flow was designed similarly to CPU instructions to minimize the complexity of the implementation of the generalized flow executor. This is important since the flow executor needs to be packaged with any programs that need to execute the flow.
Jisho with History & tAnki
Jisho means "dictionary" in Japanese. tAnki comes from the Japanese words for "short" and "memorization." The two apps which Leone developed integrate with each other to provide a full Japanese learning experience.
"Jisho with history" uses the public jisho.org API to retrieve definitions and translations for Japanese words. The app provides a resigned view of word definitions and features a history function.
tAnki is a flashcard program inspired by the Anki flashcard program.
tAnki uses spaced repetition, which is the same underlying idea, but tAnki's spaced repetition is somewhat different from Anki.
(Spaced repetition is the method of memorizing by recalling a piece of information in intervals. For example, after remembering information A, you would review A in 1 day, then 3 days, 5 days, etc. Increasing intervals is important since if memorizing a lot of information, you can spend less time on recalling information that you've already mastered.)
Purpose
Leone created this app to assist his own learning of the Japanese language. His preferred dictionary, jisho.org did not provide a 'history' functionality. Thus, using the website could lead to dozens tabs, which was difficult to manage.
Jisho with history solves the issue by putting all looked up words in a list and provides an export feature to store the words for later.
Leone created tAnki because he found that Anki didn't scale well with when memorizing tens of thousands of cards. The daily time spent memorizing flashcards on Anki had reached 3 hours, leading to burnout.
tAnki employed an algorithm that reduced the amount of time spent on flashcards for better per-card efficiency.
For an example of a Anki and tAnki algorithm difference, Anki buckets review cards into days. For example, consider a card due for review in 24 hours "A", and a card due for review in 47 hours "B". Anki could put both cards A and B in the same bucket, meaning they could both show up at the start of the day. However, tAnki does not bucket cards into days, so would show card B 23 hours after A.
Additionally, when forgetting a card multiple times, Anki will slow down the interval growth rate. While this makes sense (spend more time reviewing a harder card), this often leads to increased daily workloads when memorizing a lot of information (tens of thousands of card). Leone found the daily workload increase to be a major problem, since taking up to 3 hours(!) on flashcards was leading to burnout, Leone wanted a more lightweight, but less rigorous approach to support efficiency.
Finally, tAnki has a "graduate cards" feature, which makes cards inactive -- taking cards out of the review cycle after their interval exceeds a set amount of time. This puts a limit on the daily workload required by tAnki.
Additionally, a large portion of Leone's time learning Japanese was also spent copying cards from jisho.org to Anki. Now with both custom jisho.org and Anki alternatives, Leone was able to integrate the two apps together and remove the tedious copying.
Leone has completely switched to using his own apps for learning Japanese, and has also found use re-purposing tAnki to created flashcards to study in university, since the app allowed compete offline (no account) studying in the browser.
See https://gh.japnaa.dev/project/browse for a list of even more projects.