Intro to Theorycrafter
Theorycrafter does what the name says: it does calculations for a Genshin character. You enter a formula for an objective to optimize for, and the Theorycrafter simulates thousands of accounts for each weapon/artifact set combination. The Theorycrafter then automatically figures out which main stats are good, what sub stats to prioritize, and what is the distribution of values like stats or damage.
The result of the Theorycrafter can be saved and used in the Appraiser (TODO: not implmented yet). While the Appraiser is meant to be easy to use for anyone, the Theorycrafter is designed for more serious theorycrafters who are familiar with Genshin's damage formula and not afraid to get their hands dirty.
This tool's main motivations are the following:
- Eliminate the KQM artifact standard and replace it with a statistical model of artifact farming.
- Encourage a probabilitic view of building a character instead of summarizing a build into a single number.
- Provide a better way to rate an artifact than using the roll value, via appraiser value (AV).
- Factor in different time investments into building a character. Also deal with different account ages (older accounts tend to have access to better off-set pieces).
- Be simple to use and maintain. There is no complex UI: the build formula is just one text. Builds can be shared by just copying the text of the formula.
Please be aware of these limitations of the theorycrafter before using it:
- GAA's theorycrafter does not automatically compute damage for a given character/weapon/artifact set. GAA doesn't know much about Genshin's damage formula, character kits, or weapon passives. GAA relies on YOU to write the formula for the damage you want to optimize for. This is by design to keep the tool simple but powerful. Use Genshin Optimizer, Genshin Calculator, or gcsim for this purpose.
- GAA doesn't give an absolute artifact rating that works for everyone. While GAA is flexible and considers many factors, it cannot be the ultimate way to evaluate artifacts. Do not take the artifact ratings from GAA too seriously. Think of Appraiser Value (AV) as a slightly more sophisticated version of roll value (RV).
- GAA does not use a 100% accurate algorithm that considers every possible artifact combination to compute the best artifact set. Instead, GAA uses a heuristic that can theoretically be incorrect so that it can simulate thousands of accounts quickly. However, in practice, GAA seems to get the right answer for 99% of the simulated accounts.
- GAA's theorycrafter is more catered toward players who like to theorycraft and understand Genshin's damage formula well. It is not meant to be accessible to casual players. Stick to the appraiser if you don't know what you are doing.
- Provided example builds are made by a novice theorycrafter (me, kokokokomi222). I understand that there may be mistakes or room for improvement.
- GAA is currently in early alpha, so EVERYTHING IS SUBJECT TO CHANGE still. Keep in mind that the formula you write today may have to be rewritten in the later version. There is at least one large sweeping change to the formula syntax coming.
Example: Optimizing Fischl's Oz Damage
Let's walk through a simple example: optimizing Fischl's Oz damage, with the Skyward Harp as the weapon and the Golden Troupe 4-piece as the artifact set. You can copy this formula to the theorycrafter to see the output.
# Fischl's Oz damage main { char fischl L90 C6 1/9/9 weapon skyward_harp L90 R1 artifact 4*golden_troupe talent skill Ozs_ATK_DMG = 88.80 95.46 102.12 111.00 117.66 124.32 133.20 142.08 150.96 159.84 168.72 177.60 188.70 199.80 210.90 } maximize $Oz_Damage = talent.Ozs_ATK_DMG% * atk * Bonus% * (1+crit_rate%*crit_dmg%) * defense(100) * resist(10) Bonus = bonus+electro+skill $crit_dmg += skyward_harp.effect(20, 25, 30, 35, 40) skill += 20*golden_troupe.piece_2 skill += 50*golden_troupe.piece_4
Let's break it down line by line:
-
Line 1: Anything followed by
#
is a comment, ignored by theorycrafter calculation, but it is useful text for humans to read. -
Line 2: The keyword
main
and the curly bracket{
start the main character block, required in all GAA formulas. -
Line 3: The keyword
char
defines the character. We are working with a Fischl at level 90, constellation 6, with talent levels at 1 for normal, 9 for skill, and 9 for burst. Constellations 3 and 5 are added on top of this automatically, so it will be 1/12/12 in effect. -
Line 4: The keyword
weapon
defines the weapon. The weapon used by this formula is level 90 at refinement 1. -
Line 5: The keyword
artifact
defines the artifact set to use. We will use 4-piece Golden Troupe for this build. -
Line 6: The keyword
talent
defines a talent multiplier. We are defining a talent multiplier calledOzs_ATK_DMG
for the skill. The numbers listed after the equal sign (=
) are talent multiplier numbers. This entire line can be copied from the character help page (click the clipboard icon next to the skill damage number). -
Line 7: Curly bracket
}
ends the character block, and now we will start writing the actual formula. -
Line 9: The value
Oz_Damage
is assigned here. Since it starts with the keywordmaximize
, the Theorycrafter will try to maximize this value. After the equal sign, we see an expression. If you know how Genshin's damage formula works, this should look familiar to you. We are multiplying- Skill talent multiplier, as defined in the character block. It automatically gets 12th-level multiplier (taking C3 into account), which is 177.6% -
talent.Ozs_ATK_DMG%
- ATK. Fischl's base attack, Fischl's ATK ascension stat, weapon's base attack, and artifact main and sub stats are automatically calculated to get this number -
atk
- Damage bonus. This variable will be declared in the next line. -
Bonus%
- Expected crit multiplier -
(1+crit_rate%*crit_dmg%)
- Defense reduction by a level 100 enemy -
defense(100)
- Elemental resistance of a normal enemy (10%) -
resist(10)
%
that comes after a variable name means it is divided by 100. - Skill talent multiplier, as defined in the character block. It automatically gets 12th-level multiplier (taking C3 into account), which is 177.6% -
-
Line 11: The value
Bonus
is declared and assigned here. The general damage bonus (defaults to 100), elemental damage bonus (electro for Oz), and skill damage bonus were summed up. Prepend this line with a dollar sign ($
) if you like to see this variable showing up in the build calculations output. -
Line 13: Skyward Harp's crit damage buffing passive is implemented here.
The
+=
here will increasecrit_dmg
by the value on the right-hand side. Theeffect
function will return the appropriate value depending on whether the weapon is equipped (returns 0 if not) and also depending on the refinement of the weapon (returns the n-th value for the n-th refinement). To see all available functions in GAA, see the functions help page. The dollar sign ($
) that comes before the variable name means this buff is visible in the character details even when the character is out of the party. -
Line 14/15: Golden Troupe's 2-piece and 4-piece passives are implemented here.
The variable
golden_troupe.piece_2
evaluates to 1 if we have the 2-piece effect, 0 otherwise.
After writing a formula like this, we can run the formula with the theorycrafter by clicking the Start Theorycrafting! button.
Writing a formula
A formula for GAA is written in a
C-style syntax,
which should be similar to Excel/Google Sheet formula syntax as well.
A formula is a list of assignments,
which consists of a variable name, an equal sign,
and then an expression involving numbers and variables with arithmetic operations
like +
(add), -
(subtract), *
(multiply), and /
(divide).
The operators follow the standard order of arithmetic operations,
and parentheses (()
) can be used for grouping.
The percentage sign (%
) is used after a number or a variable as shorthand for "divide by 100".
The equal sign (=
) here means assigning the computed value from the right-hand side
to the variable on the left-hand side,
as typically used in programming languages.
It's not an equality from mathematics.
Example
Kokomi_Crit_Rate = 5 - 100 Hyperbloom_Damage = 300% * 1446.9 * (1+16*em/(em+2000)) * 0.9
Whitespaces (like spaces and line changes) are not meaningful,
but they cannot be used inside a variable name.
Comments (text you use to note things for humans but ignored by GAA)
can be started with #
and end at the end of the line.
You can also add a comment inside an expression using ^{}
syntax.
An assignment can span multiple lines,
but no two assignments can share a line.
Example
# This is a comment: both of these assignments are perfectly legal!
Sum_Of_Odd_Numbers=1+3+5+7+9+11
Sum_Of_Even_Numbers = 2 + 4 + 6 +
8 + 10 + 12 # but don't write like this, it's annoying
# Example of in-line comments
Kokomi_Healing_Bonus = 25^{Kokomi passive} + 10^{Everlasting Moonglow passive} +
15^{Ocean-Hued Clam 2-piece} + 35.9^{circlet}
Variable names can be prefixed with a dollar sign ($
)
to make their distribution visible in the "Build Calculations" output.
Variable names must be composed of
upper/lower case alphabet, underscores, and/or digits from 0 to 9,
and they cannot start with a digit.
Variable names are case sensitive, so burst_damage and Burst_DAMAGE are two different variables.
You can only use a variable in the right-hand side expression
if it is defined once on the left side of an assignment.
Some names are reserved so they cannot be used as variable names.
Such reserved names are:
char
, weapon
, artifact
, talent
, main
(see Built-in Variables for a complete list),
and all character, weapon, artifact set, and function names.
All built-in names are in snake_case
.
It is recommended that all user-defined variable names be in Title_Case
,
i.e. capitalize the first letter of each word and separate the words with underscore (_
).
Assignments can be ordered in any anyway,
but the variable defined in the first assignment must be the maximizing objective value.
GAA will try to maximize this value when choosing the artifacts.
This first variable must be visible, i.e. prefixed by $
.
GAA calculates the following automatically for you:
- Character's base stats, such as ATK, HP, and DEF
- Character's ascension stat
- C3 and C5 constellation effect
- Weapon's base ATK and main stat
- Artifact's main stat and sub stats
These must be manually implemented by you:
- Character kit, which includes skill, burst, A1, and A4 effects
- Weapon passive
- Artifact set passive (TODO: I'm considering automating 2-piece passives)
- All constellation effects except for C3 and C5
Naming Convention
All character/weapon/artifact set names in GAA follow a naming convention.
It is always in lowercase snake_case
, words separated by underscores (_
).
We replace dash (-
) and space with an underscore (_
),
and any other non-alphabet letters are removed.
For example, "Amos' Bow" becomes amos_bow
and
"Key of Khaj-Nisut" becomes key_of_khaj_nisut
.
There is one exception to this rule: family names are not used for Inazuman characters.
For example, Kamisato Ayaka is ayaka
and Yae Miko is miko
.
However, Liyue characters keep their family name
(e.g. Hu Tao is hu_tao
).
Another, but last special case is raiden
for Raiden Shogun.
Traveler must be one of the following:
traveler_anemo traveler_geo traveler_electro traveler_dendro traveler_hydro traveler_pyro traveler_unalignedOther gender-specific names like
lumine_anemo
do not work.
The character help page provides the charged attack damage numbers for both genders.
See the "Characters" help page for reference.
Character Block
A formula must have one main character block,
which is started by main {
and ended by }
.
Inside the character block,
we define the character, weapons, artifact sets, and talent multipliers.
char
defines a character.
Only one character can be defined in a character block.
A character definition consists of the following words separated by whitespaces:
char
- keyword that starts the character definition- character name - which must follow GAA naming convention
-
level - written as
L
appended by level number and optionally followed bya
if ascended from the level (e.g.L80
means level 80 but not fully ascended,L80a
means level 80 but fully ascended) - constellation - written as
C
appended by constellation count (e.g.C6
). -
talent level - normal/skill/burst talent levels,
separated by
/
and no whitespce in between (e.g.1/9/10
means level 1 normal talent, level 9 skill, level 10 (crowned) burst). Do not add talent levels obtained from constellation 3 and 5, as they are added automatically (e.g. if you have C6 Yelan but never leveled any of the talents, you write1/1/1
, not1/4/4
). TODO: handle Childe normal talent level passive nicely.
Example
char kokomi L90 C1 10/10/10
weapon
defines a weapon.
At least one weapon must be defined in a character block.
GAA allows up to 12 weapons defined in a formula (TODO: GAA is in early alpha, so this number may go up or down).
A weapon definition consists of the following words separated by whitespaces:
weapon
- keyword that starts the weapon definition- weapon name - which must follow GAA naming convention
- level - same as character level. See above
- refinement - written as
R
appended by refinement count (e.g.R5
).
Example
weapon everlasting_moonglow L90 R1
artifact
defines an artifact set to be used by the character.
At least one artifact set must be defined in a character block.
GAA allows up to 12 artifact sets defined in a formula (TODO: GAA is in early alpha, so this number may go up or down).
It may be more accurate to say that the artifact definition defines the farming plan for the simulated accounts.
For example, if you specify a 4-piece VV set,
the theorycrafter will simulate each account to farm the VV domain for three weeks' worth of resin
and strongbox bad artifacts into VV for three weeks as well.
After that, the theorycrafter will look for the best 4-piece VV set to equip.
An artifact set definition consists of the following words separated by whitespaces:
artifact
- keyword that starts the artifact set definition-
artifact expression - for 4-piece set effect, write
4*{SET_NAME}
. For 2+2 piece set effect, write2*{SET_A_NAME}+2*{SET_B_NAME}
. Set names follow GAA naming convention.
Example
artifact 4*ocean_hued_clam
How accounts are simulated
Theorycrafter simulates thousands of accounts for each weapon/artifact set pair in order to figure out main stats, sub stats, and variable distributions. This section describes how the simulation works.
A GAA simulated account reaches AR45 after the first 12 weeks and AR55 after another 12 weeks. We define an account to be "active" if they are not wasting any resin and are over AR45. The default "active" number of weeks is 40, which roughly represents a 1-year-old account. We also have a "farming" period where resin is mostly spent on an artifact domain for our specific character. By default, the farming period is 3 weeks. Each simulated account will obtain artifacts from six different sources:
- Normal bosses - which drop Wanderer's Troupe or Gladiator's Finale. The default value is 4 5-star artifacts per active week. The probability of a 4-line artifact is 33.3%.
- Weekly bosses - which drop Wanderer's Troupe or Gladiator's Finale. The default value is 3 weekly bosses per active week (the actual number of artifacts depends on luck. An extra 5-star artifact is assumed to drop 23% of the time). The probability of a 4-line artifact is 33.3%.
- Off-set farming from domain - which represents off-set artifacts that accumulated over the time the account was active. The probability of a 4-line artifact is 20%. The default value is 600 resin spent on artifact domain per active week (the actual number of artifacts depends on luck An extra 5-star artifact is assumed to drop 6.5% of the time), but this can be increased with resin recharge.
- Off-set strongbox - which are off-set artifacts that accumulated from strongboxing over the time the account was active. This also includes artifacts obtained from domain reliquaries, which results from Spiral Abyss clears. The probability of a 4-line artifact is 33.3%. The default value is 12 5-star artifacts per active week.
- On-set farming from domain - which are actively farmed for our specific character. The probability of a 4-line artifact is 20%. The default value is 1200 resin spent on the artifact domain per farming week (the actual number of artifacts depends on luck An extra 5-star artifact is assumed to drop 6.5% of the time), but this can be increased with resin recharge. This is not available for Wanderer's Troupe or Gladiator's Finale.
- On-set strongbox - which is only available for some sets. The probability of a 4-line artifact is 33.3%. The default value is 20 5-star artifacts per farming week.
Artifact quality is then evaluated by Appraiser Value (AV). All artifacts are fully leveled, then artifacts with low AVs are destroyed. (earlier versions of GAA did proper leveling simulations, but they were found to be slow and get to very similar numbers as this crude version). Using these artifacts, GAA looks for the best artifacts to equip that maximize the objective value.

Before the accounts can be simulated, AV weights (scores on main and sub stats) must be calculated. AV weights are computed iteratively by considering the linear gradient of the objective function at the optimal value, which is approximated by simply averaging a bunch of simulated results. Build optimizer is initially set to strict (looks at a lot of artifact combinations), but as AV weights get better, the build optimizer loosens up.
Our objective function is not truly differentiable or even continuous. For instance, crit rate is capped at 100%, so the damage usually climbs linearly as crit rate increases but flattens out at the cap. Also, if a build formula requires 160 ER, the value of the ER substat changes drastically depending on the discrete choice of equipping ER sands. Even so, this crude linear approximation seems to perform well in practice at ranking valuable artifacts. After AV converges, GAA is able to find the correct optimal set >99% of the time by only looking at ~700 combinations (for 4-piece sets).
Formula Version 3
After using version 2 for a few months myself, I would like to implement some new features. Below are some ideas for version 3. Some of these may get implemented, but nothing is set in stone right now. All examples provided below are just idea sketches and the syntax will likely change.
Rotation timing and time-dependent buffs
Some buffs gain/lose stacks as time goes on, such as Furina's fanfare or Mavuika's A4. Also it's annoying in version 2 to separate out attacks that receive certain buffs (e.g. Bennett's burst lasts 12 seconds, so not all damage in a rotation may benefit from it). It would be nice to be able to specify time for each attack instance and duration for each buffs. Sort of like how Kol's Calc Template list all the invisidual hits. Maybe gcsim samples can even be imported eventually.
damage 0 Burst_Damage = talent.Burst_DMG% * atk buff 0-12 atk += talent.Burst_Buff% * base.atk
Random variables
The Widsith is incredibly annoying to implement right now. Also if an attack is known to vape 60% of the time, it's not nice to show in the build output, because we have to separately output the numbers. These problems can be solved by introducing a "random variable". It doesn't actually use any randomness in the calculation; instead the computation will take every possible realization of the random variable and take avarage (or maximum) at the end. Crits are already handled in a similar manner already, so this should not be too difficult to implement. However, too many random variables can exponentially affect performance. Random variables are pairwise independent and resolve in the reverse order of the declaration.
# widsith random buff. Objective is the maximum of the three (e.g. for screenshot build) random Widsith_Buff = maximize Recitative Aria Interlude atk_pct += the_widsith.effect(60 ) * Widsith_Buff.Recitative hydro += the_widsith.effect(48 ) * Widsith_Buff.Aria em += the_widsith.effect(240) * Widsith_Buff.Interlude # 60% chance to vape. Objective is the expected damage random Vape = average Yes(60%) No(40%) Damage = talent.Hit_DMG% * atk * (Vape.Yes*vape_with_hydro(em) + Vape.No)
Team buff
Maybe team buffs can be parametized so it can actually use your support character's level/weapon/artifact set/talent level/constellation. This way, elemental resonance can be automatically checked as well. This could eventually lead to automatically calculating ER requirement by running energy simulation of the team.
sub { char furina L90 C0 9/9/9 weapon splendor_of_tranquil_waters L90 R1 weapon favonius_sword L90 R1 artifact 4*golden_troupe talent burst Fanfare_to_DMG_Increase 0.07 0.09 0.11 0.13 0.15 0.17 0.19 0.21 0.23 0.25 0.27 0.29 0.31 } bonus += furina.talent.Fanfare_to_DMG_Increase * 300 energy += furina.favonius_sword.effect()
Farming parameters
Artifact farming parameters can only be adjusted in the source code as of now. I want to move this out to be configured in the formula text.
main { char kokomi L90 C6 10/10/10 weapon everlasting_moonglow L90 R5 artifact 4*heart_of_depth farming { time_active = 3 year, time_farming = 1 year, resin_recharge = 5, num_weeklies_per_active_week = 3, num_bosses_per_active_week = 4, num_condensed_domain_per_active_week = 15, num_strongbox_per_active_week = 12, num_condensed_domain_per_farming_week = 30, num_strongbox_per_farming_week = 20, farmed_domain = heart_of_depth+blizzard_strayer, } }
Custom Character/Weapon/Artifact Set
GAA should be able to accomodate any character/weapon/artifact set you dream up with little effort.
main { char paimon L90 C0 9/9/9 = new char( stat_curve=5, atk_1=24.24, atk_90=333.77, hp_1=1234.56, hp_90=12345.67, def_1=50.00, def_90=600.00, ascend_stat=crit_rate, C3=skill, C5=normal, weapon_type=catalyst ) weapon emergency_power L90 R1 = new weapon(star=5, main_stat=atk_pct, main_value=674, weapon_type=catalyst) artifact 4*secrets_of_celestia = new artifact(star=5) talent normal Normal_DMG = ... talent skill Buffmon_Buff = ... } maximize Normal_Hit = talent.Normal_DMG% * atk * (bonus%+Light%+normal%) * (1+crit_rate%*crit_dmg%) * defense(100) * resist(10) Num_Food_Eaten = 3 # eating adeptus temptation, light damage potion, any defense/recovery food atk_pct += talent.Buffmon_Buff + 20*Num_Food_Eaten*paimon.a1 Light = 50*paimon.a4^{assuming traveller is in the party} + 15*secrets_of_celestia.piece_2 + 25^{light damage potion} atk_flat += 372 # adeptus temptation crit_rate += 12 # adeptus temptation atk_pct += Num_Food_Eaten * emergency_power.effect(20) bonus += Num_Food_Eaten * emergency_power.effect(10) crit_dmg += 70*secrets_of_celestia.piece_4
Localization
Allow outputing the variables names in different languages in preparation for supporting other languages.
# @title On-field Kokomi # @title-ko 온필드 코코미 $Jelly_Heal^{@trans ko="해파리 힐량"} = (talent.Jelly_Heal_HP% * hp + talent.Jelly_Heal_Flat) * (1+heal%)