Introduction
I created the Visual Novel Recommender because I wanted to find visual novels to read that appealed to me. While VNDB offered a good selection of highly acclaimed visual novels, I found many of them not quite being to my tastes. I wanted to find visual novels that were of genres or had characteristics that I cared about, while also not ignoring what had gotten a more positive reception from other people.
So I created a tool that takes the overall user-given score of each visual novel as a basis and adjusts it based on your own personal preferences. It's all made possible by the Visual Novel Database and its amazingly in-depth user-voted tag system. It is updated every day with new visual novels and up-to-date information.
By default, the site just displays the highest-rated visual novels overall. This is not too different from the list VNDB shows, so you should probably customize the list according to your preferences in the sidebar. If you feel a bit lost on how to use the site, then Finding good VNs offers subjective suggestions on methods I've found to be useful for getting desirable results to rise to the top of the list, while Preferences gives a more technical overview of the settings.
Visual novels with fewer than a total of 30 points from user votes are not listed.
A VN listing
Each page lists visual novels according to their score, in descending order, from left to right, top to bottom. There are two different layouts that can be toggled between with Preferences ⇾ Miscellaneous ⇾ Use layout with large images. The default layout has a small image on the left and can be clicked on to expand the listing and reveal more information. The alternative layout has the image as the background and must be hovered over to see any information. The layout of the information is otherwise identical, and the following is the expanded default layout.
A VN listing has the following parts, from top to bottom:
- Its name. Hovering over it reveals it in full if it was otherwise truncated. Clicking on it takes you to its VNDB page.
- An that toggles its blacklist state, taking effect the next time the list is generated.
- Its total score. This is the base score adjusted by your preferences.
- Its estimated length based on user votes.
- The release date of its first "complete" release.
- Languages it's available in. The original language it was released in is listed first. The rest are in a fixed order. I have chosen to only track the 8 most popular languages for visual novels - Japanese, English, Chinese, Russian, Spanish, Korean, French, and German. If you see letters, not flags, then your browser does not support country flags.
- Its most relevant user-voted themes.
- The score breakdown, consisting of the following parts:
- The base score, calculated from the average user-voted score and the number of user votes. The average is calculated as a 10/10 vote being 100%, and a 1/10 vote being 0%.
- A table, first containing all the themes of the novel in descending order of relevancy. The relevancy percentage is shown in the first column. Then followed by other aspects of the novel that you expressed a preference for or against, in descending order of how positively they affect the score. The amount of Preference Points they affect the score by is shown in the last column. More about all this under Preferences.
- The total, showing again the base and final score, as well as the total Preference Points.
Finding good VNs
The following are just my personal opinions on how to use the site, accompanied by examples based on my own preferences. If you don't agree with something or want to do things differently then feel free to ignore them.
The recommender is mostly intended for people who have already read at least some visual novels or have opinions on the kinds of things they would or would not want to read. If you just want anything, then you can probably pick one of the highest-rated visual novels and go with that.
For everyone else, one option is to just go over each setting under preferences one by one and take a guess at where you might want each slider to be. The problem with that is that it's difficult to intuitively grasp how much each setting affects the results. Setting everything to one extreme or the other probably isn't a good idea, but otherwise, the ideal values are very subjective. I can tell you that each tick on a slider represents one "Point", and the difference in score between the top novels and mediocre novels is about 20 "Points". If it still feels like you're fumbling in the dark and the suggestions are no good, read on.
Whether you chose to try the first option or not, you can look at the top suggestions and try to identify if there are some recurring things in them that you dislike. For example, most of the highest-rated novels are longer than 50 hours, but I don't have that kind of time, so I set the length preference to 30 hours max and removed 1 point per 10 hours. There still seemed to be too many long suggestions, so I started decreasing it until I arrived at -1 points per 3 hours, at which point the length was no longer a point of discontent among the top suggestions. You can repeat this process with other recurring things you dislike until the suggestions start to seem better.
The idea here is to be conservative with adjusting your preferences. If you dislike something, remove the minimal amount of points possible for that thing to no longer be at the top. Because you only see the suggestions at the top, it's much easier to see when something is rated too highly, but once you dock too many points, you won't notice something might actually have fallen too low.
Of course, just removing points is only using one half of the possibilities, but I believe the second half is a bit more difficult. I don't have an answer to how much you should initially give points to things you like, but as an example, when I set 5 Themes to their maximum values after having already removed some points from other options I disliked, I noticed there were a lot of novels with low base scores. These probably weren't ideal recommendations, but instead an indicator that I had set my preferences too extreme. The base score, or what you could consider as the actual base "quality" of the novel was being completely overshadowed by my preferences. I think this is something to avoid.
Whatever you choose to do, don't worry too much about it. It's not a science. Just play around with the settings. The more you tweak things back and forth, the better your understanding of them will be, and you'll be able to find the best recommendations soon enough.
PS. The "Miscellaneous" section contains many options that don't affect the score but instead filter the results. You can keep these at their default values while fiddling with the other options, just to get a better idea of the kind of things suggested to you, but you probably want to filter to only languages you can read, tick all the "Hide" boxes because you probably want to start with the original story, and hide the novels you've blacklisted. You can also import your finished, dropped, blacklisted, etc. novels from VNDB to serve as the blacklist.
Preferences
Preferences provide the main functionality of the site, helping you bring the novels you actually care about to the top. Some preferences are filters, outright removing some results from the list, but most only change the score. The entire scoring system is based on Preference Points (PP). Each positive PP increases the score of a VN by 2%, and each negative one does the opposite. More precisely, the final score of a VN is baseScore * 1.02totalPP
. Most preferences are sliders with 21 ticks. Each tick represents 1 PP, going from -10 to +10 PP. They are divided into 5 categories.
- The first category is themes, separated into 10 of the most popular themes/genres I could identify VNs having - Fantasy, Romance, Drama, Comedy, Mystery, Crime, Sci-fi, Action, Slice of Life, and Horror. Every VN has one or more themes (except for unpopular ones where no theme tags or subtags have been applied). The sum of all the themes has been normalized to 100%, meaning all the themes of a VN combined can't give more than +10 PP nor less than -10 PP. Each theme gives points proportionally to how much it applies to the VN.
- The second category, other, has the following preferences:
- Length - Allows you to specify a length range and the falloff rate. Anything within the specified range receives no penalty to its score, while anything over or under that length receives -1 PP per the specified amount of hours over or under that length.
- Age - The age of the novel (not the characters). Otherwise functions identically to the Length preference.
- Branching - I have identified 6 tags that indicate how much the plot of a VN does or does not branch, and given each a weight from -20% to +80%. They are - Kinetic Novel: -20%, Single Ending: 0%, Linear Plot: 20%, One True End: 40%, Branching Plot and Multiple Endings: 80%. That weight is multiplied by this setting.
- Sexual Content - I have identified 5 tags that indicate how much sexual content there is in a VN. These have been given weights from 0 to 200%. They are - None: 0%, Low: 50%, Regular (no adjective): 100%, High: 150%, Nukige: 200%. That weight is multiplied by this setting.
- Gameplay - Aside from no gameplay, a VN may have Light or regular Gameplay. VNs that only have Map Movement and/or Interactive Adventure Game tags are considered Light Gameplay and make your gameplay preference only give half of its value. The VN may additionally have Optional and/or Skippable Gameplay tags, which further make your gameplay preference only give half of its value, if it is negative. Every other subtag of Other Gameplay Elements is considered regular Gameplay.
- The third category, source/type, has the following preferences:
- Adaptation - Whether the VN is Based on a Manga, Light Novel, Web Novel, Anime, or other preexisting source material.
- Fanfiction - Whether the VN is fanfiction.
- Otome - Whether the VN is an Otome Game.
- The fourth category, miscellaneous, does not affect PP. It is mostly filters, but also has some other settings. They are as follows:
- Prefer niche / popular - Adjusts the base score of each VN. Niche favors VNs with a higher average user vote, caring less about the amount of votes. Popular favors a high amount of votes, caring less about the average vote score. This setting may seem to have a low impact on the top of the list because the VNs there are both highly rated and popular, but it has a much bigger impact on VNs that are ranked lower, and thus a bigger impact after those lower ranked VNs surface after applying your preferences. The base score is defined as
averageRating * (1 - (votes + 1)-(1 / log2(scoringWeight)))
, withscoringWeight
being from 4 (niche) to 8 (popular). - Languages - Filters to only include VNs that have a complete release in one of the chosen languages. Selecting none of them is the same as selecting all of them.
- Hide sequels & prequels / side stories / fandiscs - Excludes VNs which are categorized as the ticked option. These relations are transitive with one another, meaning that, for example, even if a VN is not marked as a side story, but a sequel, excluding side stories would exclude it if it is a sequel of a side story. In other words, a sequel of a side story is still a side story. Similarly, a fandisc of a sequel is still a sequel, etc.
- Results / page - How many VNs to show per page. Limited to 200 for everyone's safety.
- Blacklisted novels - "Hide" hides VNs you've blacklisted. "Show" shows all VNs, including those you've blacklisted. "Show only" shows only the VNs you've blacklisted, perhaps useful if you ever want to unblacklist any of them.
- Use layout with large images - Switches between the default and the large images layout, briefly described in the first paragraph of A VN listing.
- Hide NSFW images - Hides images which have been flagged as erotic or violent.
- There is one more setting outside the Preferences menu, under Advanced - Preference Point weight. I do not recommend most people change it, definitely not if you don't understand what it does, but if you feel your preferences are changing the scores too much or not enough, you may tweak this setting.
- Prefer niche / popular - Adjusts the base score of each VN. Niche favors VNs with a higher average user vote, caring less about the amount of votes. Popular favors a high amount of votes, caring less about the average vote score. This setting may seem to have a low impact on the top of the list because the VNs there are both highly rated and popular, but it has a much bigger impact on VNs that are ranked lower, and thus a bigger impact after those lower ranked VNs surface after applying your preferences. The base score is defined as
- The last category allows adding custom filters. It is limited to tags that can be applied to a VN, as well as all their parent tags. A tag is considered to match the custom filter if the custom filter is the tag or is a parent of the tag. For example, excluding the Fantasy tag also excludes all VNs tagged with Magic, because anything with Magic is a Fantasy. However, excluding the Magic School tag does not exclude all VNs with Magic, because having Magic doesn't mean there is also a Magic School. Aside from excluding a matched tag, you can alternatively choose to include it, or give it a PP value with a slider.
- The "Do not apply to spoilers" checkbox makes custom filters respect the spoiler state of tags. Enabling this setting thus reduces the accuracy of custom filters, but prevents spoilers. In case you're filtering or scoring by tags that are almost always spoilers, such as tags about certain characters dying, you probably want to turn this setting off.
Presets
Presets allow you to save all your current preferences under a name of your choosing to quickly switch back to at a later date. After adding a preset, you can change your preferences however you want, and if you ever click on the saved preset again, it replaces all of your current preferences with the ones you saved earlier. This does not save or change your blacklist, but it does change your active custom function.
The default Reset preset resets all preferences to their default values.
Import / Export
The Visual Novel Recommender remembers your browsing sessions and saves all your preferences, presets, and most everything else on the site. This data should not be lost unless you uninstall your browser, run out of disk space, or remove it manually. If you wish to create a backup of your data or export it for use on another device, then you can do so with the "Export / Backup" button. It can also be used if you wish to share your presets or custom functions with other people.
If you wish to quickly synchronize your blacklist with your VNDB list, you can import your previously exported Visual Novel List. To export that, you must be logged in to VNDB, navigate to "My Visual Novel List" in the sidebar, and then choose "Export". The recommender operates locally on your device, so even if you're concerned about your privacy, none of the data will ever leave your device.
Finally, you can import a previously created Visual Novel Recommender export. You can separately choose whether or not to import your current preferences, presets, blacklist, and custom functions. "Overwrite" will first remove all the data of that category and then add all the data in the imported file. "Append" will replace data with the same keys (preset names, all settings, custom functions with the same names), but otherwise leave your previous data intact, only adding the data in the imported file. "Unused" will not use the data for the category in the imported file. Do not import custom functions from sources you do not trust, as it allows them to run arbitrary code in your browser.
Custom functions
This section is not intended for most users, but if you wish to entirely replace the filtering and scoring procedure for the site, you may write your own custom function. Start by entering a name for it, click "Add", and then click the icon to edit it. The box that opens will contain the equivalent of the code used without a custom function. If you wish to change some minor things, then you can just edit the existing code. If you wish to make more extensive changes, then you might want to read ahead.
All custom functions are written in plain JavaScript, but I will be using TypeScript syntax to explain the types of function parameters, return types and class fields. You may have a better experience writing these functions in a dedicated code editor and pasting them back here.
I will not go into detail on what my existing code does. You should be able to guess most things by reading the code and reading through the A VN listing and Preferences sections. I will, however, provide a list of types that you may need to know.
You are expected to write the body for the following function, which will be called for each visual novel every time a preference is changed:
(vn: VN, settings: Settings, Tag: typeof Tag) => boolean
A VN
is an object with the following properties:
title: string
id, imageId, votes, rating, length, baseScore, score: number
release: Date
isSequel, isSideStory, isFandisc, imageIsNsfw, fanfiction, otome, hidden: boolean
originalLanguage, languages: Language
sexualContent: SexualContent
branching: Branching
gameplay: Gameplay
source: Source
tags: Map<Tag, { value: number, isSpoiler: boolean }>
genreCoefs: { genre: Tag, coef: number }[]
scoreComponents: { text: string, addPP: number, coef?: number }[]
hasTagName: (name: string, hideSpoilers = false) => boolean
hasTag: (tag: Tag, hideSpoilers = false) => boolean
originalLanguage
, sexualContent
, branching
, gameplay
, and source
are simply number
values (and languages
is a bit field) described by the following enums:
enum Language { Other = 0, Japanese = 0x1, English = 0x2, Chinese = 0x4, Russian = 0x8, Spanish = 0x10, Korean = 0x20, French = 0x40, German = 0x80 }
enum SexualContent { Unknown = -1, None = 0, Low = 0.5, Regular = 1, High = 1.5, Nukige = 2 }
enum Branching { Unknown = -1, Kinetic = 0, SingleEnding = 1, LinearPlot = 2, OneTrueEnd = 3, BranchingPlot = 4, MultipleEndings = 5 }
enum Gameplay { None = 0, Light = 0.5, Other = 1 }
enum Source { None = 0, Manga = 1, LightNovel = 2, WebNovel = 3, Anime = 4, Other = 5 }
tags
is a list of all the tags of this visual novel, their corresponding relevancy, and whether they are a spoiler, similar to VNDB's system.genreCoefs
is a list of all the genres/themes applicable for this visual novel.scoreComponents
is the list that is used to create the score breakdown table. text
is the text in the middle column, addPP
is the number in the last column, and coef
is the optional percentage in the first column.hasTagName
and hasTag
both check if the VN has the specified tag or any child of the specified tag. Tags that are spoilers are not checked if hideSpoilers
is true
.
A Tag
is an object with the following properties:
id: number
name: string
parents: Tag[]
hasChildren: boolean
allParents: Map<Tag, number>
isSubTagOfTag: (tag: Tag) => boolean
isSubTagOf: (name: string) => boolean
subTagDepth: (name: string) => number
parents
is a list of only the tag's immediate parents, while allParents
is a list of all the tag's parents up to the roots and their corresponding distance.subTagDepth
is an alternative index to allParents
, using a string
key instead. Returns -1 if the tag does not have a parent with the specified name.
isSubTagOfTag
and isSubTagOf
both check if the tag is a child of the specified tag.
The Tag
passed to the initial function can be used to reference static fields of the Tag
class.static allTags: Tag[]
- a list of every single tag.static nameMap: Map<string, Tag>
- a map from the name of a tag to the tag itself.
Finally, Settings
is the object that contains all your preferences.
fantasy, romance, drama, comedy, mystery, crime, sciFi, action, sliceOfLife, horror, minLength, maxLength, lengthDropoff, minAge, maxAge, ageDropoff, branching, sexualContent, gameplay, source, fanfiction, otome, scoringWeight, languagePrefs, vnsPerPage, ppWeight: number
hideSequels, hideSideStories, hideFandiscs, useBigLayout, hideNsfwImages: boolean
hidingState: "Hide blacklisted novels" | "Show blacklisted novels" | "Show only blacklisted novels"
blacklist: Set<number>
excludedTags, includedTags: Set<string>
customTags: Map<string, number>
activeCustomFunction: string
I catch any obvious errors from incorrectly defined custom functions, but if you mess up really badly, like writing an infinite loop, you can press F12, navigate under Storage, Indexed DB, VNDB, customFunctions, find the troublesome function, and delete it.
VNDB data dump
All the data used on this site has been acquired from the VNDB database dump. I trim the vast majority of data, so if you're looking for data on visual novels, you're probably better off using VNDB's dumps or API. However, if you wish to use my version of the data instead, then you are free to do so. You should make a local copy of the dump, which can be acquired from ./dump.br
. It is updated once a day, before 10 AM UTC. Please do not download it more than once a day, or I may have to restrict access to it.
It is compressed with Brotli and is in a binary format after decompression, comprised mostly of variable-length integers and length-prefixed (also a variable-length integer) strings. All values in the following description are variable-length integers unless noted otherwise. Dates are represented as the number of days since January 1, 0001.
The first value is the date the dump was created. The next value (tagCount
) is the number of tags. The next tagCount
groups of values are the tags. Each tag's ID is their index in this array. A tag is the following values: The name as a string, the number of parent tags it has, and the IDs of its parent tags.
The next value (vnCount
) is the number of visual novels. The next vnCount
groups of values are the visual novels. A visual novel is the following values: The ID, the image ID, the title as a string, the number of votes, the average vote multiplied by 100, the length in minutes, the release date, the original language as a single byte, all the available languages as a single byte, miscellaneous data as a single byte, the number of tags, and finally the tags as pairs of values. Each tag is its id, followed by its relevancy as a single-precision floating-point number.
Both language bytes and the miscellaneous data byte are bit fields. The original language byte has 0 or 1 bits set, while the others have 0 or more bits set. The language byte has the following flags, starting from the least significant bit: Japanese, English, Chinese, Russian, Spanish, Korean, French, German. The miscellaneous data byte has the following flags, starting from the least significant bit: Sequel, Side story, Fandisc, NSFW image.