Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
SatoruGojo
Satoru Gojo as a playable survivor, and the library the other three Jujutsu Survivors are built on. Install this on its own for Gojo alone.
By Marmennz
CHANGELOG
Changelog
1.1.7
And the pale patch on his cheek is gone. Each of the three outfits ripped
from the game's own files carried a facial overlay — slot16 on the day-off and
the shirtsleeves, slot20 on the uniform, about two hundred triangles each —
weighted to the MMD rig's face and jaw_A bones and wearing the hair
texture. It is invisible in the rest pose and smears across the cheek and jaw as
pale streaks the moment the character animates, which is why it survived every
look at the models until now.
Found by elimination rather than by argument: the head was rendered once with everything, then once per part with that part hidden, and the patch belongs to whichever render loses it. Colour-coding the parts was tried first and gave two confident wrong answers, both of them the background.
tools/drop_part.py cuts a part out of a .model in the bytes, same as
flip_winding.py does with the winding: the part count drops by one and every
other part, every bone and every vertex comes through untouched, which is what
was checked afterwards against the file in git.
Gojo's animations are mirrored, so he reads the same way round as everybody else. Every other character here is drawn as the mirror image of his own vertices — the model files are wound inside out and the model root carries a negative X scale, and the two cancel into a correctly lit body. Gojo is cloned from Commando, has no such scale, and is drawn true, so the clips he shares with Sukuna came out the other way round on him.
The transform was the obvious place to fix that and it was the wrong one. A
negative X on his model root inverted the lighting on every skin and tore the
poses off the two outfits that ride proxy skeletons: GojoOutfitRig drives those
with world rotations, and a mirrored ancestor makes a world rotation
meaningless. The animation driver escapes it by writing localRotation, which is
the whole reason the other three animate correctly under their own mirror. That
attempt was reverted the same hour it shipped.
So the data moves instead, and nothing about rendering changes.
tools/mirror_clips.py reflects a library left to right: every bone whose name
says Left trades places with its Right twin, and every rotation is reflected
across the sagittal plane — applied to each clip's rest as well as to its
samples, since the driver applies the difference between them and a mirror on
one of the two is not a mirror at all. His standing, walking and running are
copied in from sukuna.anim and mirrored with the rest rather than borrowed
unmirrored at load, including the Lower_ set the leg-under-a-cast layer asks
for by name, because a mirrored body over borrowed legs is worse than either.
Twenty-one clips where there were eleven; nothing is borrowed at runtime now.
Rendered before shipping, as the last two attempts at this should have been:
Flight and Idle both come out as clean mirrors of themselves.
And the title screen says which way round each character is drawn. Asked of
the camera rather than of the transform, because a transform under a negative
scale still reports a right that points the way its basis does and not the way
the body is drawn — which is the confusion that cost two wrong fixes. A character
facing the lens wears his own right hand on the viewer's left, so a right hand
landing on the viewer's right is a character drawn mirrored, whatever his scale
says. The scale of every object from the hand up to the root is printed with it.
Gojo makes his own hand sign when he stands still, instead of Sukuna's. He
had no idle clips whatsoever — gojo.anim ships casts, flight, punches and the
domain, and not one idle — so the borrowing that fills his standing and walking
from sukuna.anim was also handing him IdleVariant and IdleVariant2, which
are Sukuna's idle breaks and Sukuna's gesture.
He has one of his own now, built out of the sign his domain already holds:
standing, the hand raised into the sign, held, and lowered back to standing, at
30fps over 2.93 seconds. The two borrowed breaks are off his list, so the only
break he can play is the one he owns — a character's clip wins the name it
answers and only that name, and leaving IdleVariant2 there would have kept half
of them.
tools/author_gojo_idle.py writes it, and three things in it were found by
looking rather than by reasoning:
- The delta a clip stores is
rest^-1 * sample, with the inverse on the left. Written the other way it survives a transfer between clips that share a rest and wrecks one between clips that do not — which is why the standing frames came out perfect and the gesture put his torso through a quarter turn. - Only the arms and hands take the gesture.
Domainon its own is a whole cast: torso wound over, head laid back, feet planted wide, half of which a run overrides with the leg layer. An idle break has none of that around it, so the torso brought the wrench with it. - Feet do not move — the hips and both legs hold the standing pose for all 88 frames, measured at 0.000 degrees of leg motion across the clip, and the first frame matches the last to within 0.04 degrees so the break starts and ends where standing left off.
Rendered before shipping, on the calibration the tool asks for: Flight on the
formal skin first to prove the harness, then the hold frame of the new clip.
And the outfits themselves are built on the live character rather than on the prefab it is cloned from. The rig that drives them keeps its proxy skeleton, the live bone each proxy follows, and the rotation between them, in plain private fields — and Unity serializes no such field, so the component reached every clone holding nothing at all. The meshes came across, because they are objects, and stood in the pose they were authored in while the skeleton underneath them animated perfectly. Building on the prefab is what Yuji does and it is right for him: his outfits bind straight to the live bones and keep no state to lose.
Second, he stood in his bind pose. His clip resolver has cases for his casts, his flight and his strikes, and none for standing, walking, sprinting or the character-select stance — those were answered by the rig behind it. A refusal now reached nothing, which is the flat T-pose with the arms straight out.
Third, he was drawn on the title screen and in character select with a shader
that shows nothing. He was never missing from either. He stood at his place in
the frame with his feet on the ground, animating his lobby idle, wearing the
skin he was asked for, group switched on, renderers enabled, all fifty-two bones
attached, and his box measured on screen at exactly the empty space where he
belongs. The material every one of those meshes was cloned from carried
Hopoo Games/FX/Distortion — a screen-space pass that draws no colour at all —
while the other three characters carried Hopoo Games/Deferred/Standard.
The imported meshes take their material from the model they replace, and what was asked for was the first material on it rather than a material that can draw a body. A shader that draws a textured surface is what is asked for now.
That alone was not enough and the log said so: CommandoDisplay has nothing of
the kind anywhere on it — no materials in its renderer list to recolour, and the
only one under its model is matBrotherSwingDistortion, which is what was being
drawn. So a display falls back to the material the body prefab already produced
for the same character rather than to whatever is nearest, which is the same look
instead of a substitute for it. The old lenient search stays as the last resort,
and the material, its shader and where it came from are all named in the log —
because "the mesh was never built" and "the mesh is drawn by a pass that shows
nothing" are indistinguishable in a screenshot and were confused for two
releases.
Two other explanations were tried on this before it was measured, and both were wrong — one of them took a working run down with it. So the title screen also reports what each of its four characters actually puts on screen now: renderers drawn, their combined box in the world, where it lands on the screen, the layer, the shader and the bone counts. Three characters answering one way and one answering another is what named this in a single run, after two releases of reasoning had not.
Four of his six skins were drawn inside out, and now are not. They were
see-through — the background visible through his chest — and lit from the wrong
side, which reads as far too dark. Backface culling was removing the surface
facing the camera and keeping the one behind it, because the triangles in three
of his model files are wound against their own normals. Measured, not guessed:
the share of triangles whose winding agrees with their vertex normals was 3.3%
in satoru.model, 2.3% in shinjuku.model and 3.3% in gojo-formal.model,
against 97.9% and 98.2% in the two files whose skins looked right. Four skins
come off the first three and two off the last two, which is the split exactly.
Every older asset in the mod is wound that way, Yuji's and Sukuna's and Todo's
included, and theirs are correct on screen because their model root carries a
negative X scale from the prefab they were cloned from — a mirror flips the
effective winding back. Gojo's root comes from CommandoDisplay and is not
mirrored. So the fix is in his three files rather than in the loader they share:
mirroring his root instead would have inverted the two files that were already
right, and touching the loader would have inverted three other characters.
tools/flip_winding.py reverses a .model's winding in place in the bytes —
same length, nothing but the index lists touched, and the index set of every
part unchanged, which is what was verified afterwards along with the bones,
vertex counts, part names and textures. The three files now measure 96.7%, 96.7%
and 97.7%.
Two parts of shinjuku.model are still drawn white: Squinty_Eyes_0, one per
outfit, 78 triangles each, carrying no texture name at all. Every other
expression overlay in that file uses ntxr010.png and so should these, but
writing a texture name changes the length of the file and wants a real writer
for the format rather than the byte surgery above.
And a diagnostic grid, behind the console command jujutsu_grid. It stands a
hundred copies of Gojo in a ten by ten grid on the title screen, each built a
different way — where the material comes from, what is stripped off the copy
before it is allowed to run, whether the mesh stays skinned or is baked flat, and
whether the model is mirrored, which was the one measured difference between him
and the three characters who were visible. Every cell is logged with its place on
the screen and the four methods that made it, and the top left cell is the
shipped construction. jujutsu_grid 0 clears it and puts the line-up back.
It confirmed the fix above in one launch — all hundred cells drawn, all of them
through Hopoo Games/Deferred/Standard, the top left one included — after two
releases of reasoning had produced two wrong answers. It also earned its keep the
awkward way: it shipped as a setting defaulting to on, and because the grid stands
in place of the line-up, that launch hid the very thing it had just proved
fixed. Hence a command, asked for out loud, and hence the setting carrying a v2:
a default changed in code never reaches a key a config file has already written.
His resolver is asked first and the shared one takes over when it declines, instead of a decline ending the search. The shared path is what already picks between idle variants, reads the configured lobby stance and normalises a walk cycle by phase, all of which he now wants and none of which is specific to him.
A refused pose is written to the log for him too. It was silenced on the grounds that his set answered three poses by design and something else took the rest, so a refusal said nothing. Nothing stands behind him now, and the run that produced the bind pose produced a log with no line about it in — which is most of why it took a second look to find.
Three things had to be found in testing before any of the above worked, and all three were left behind by the rig that went away.
First he had no body at all. The component that decides which of his meshes is on screen owns the visible set and forces it every frame, and it takes a single renderer to do it, because the rig it was written for drew the whole character with one. A rig read from a model file draws with six, so five of them could not be shown under any circumstances, and the sixth only while no outfit was chosen.
It is gone. His own meshes go into a named group like every outfit, and the suit is registered as an ordinary skin that switches that group on and the others off — which is how Yuji's have always worked. Nothing watches and corrects anything now: the game switches one object on and the rest off.
The formal suit is therefore the skin the rig itself wears, and it is no longer
also offered out of satoru.model, which would have put the same mesh on
screen twice. Six skins, same as before.
Gojo no longer ships anyone else's mod, and no longer names it either. The package carried two asset bundles that were not ours: one holding a whole other survivor, and one holding a skin somebody made for it. A Thunderstore moderator refused an upload over them and was right to. Both are gone.
The code that loaded them went with them, because the files being absent is not
the same as the mod being clean: the assembly still carried
"sett_animations.bundle" and "gojo_sett_skin.bundle" as string literals, a
component and a field named after that character, and a rig report that talked
about him — all of it readable straight out of the IL, which is the level an
upload was once refused at over nothing more than a method called LoadLibrary.
Three files are gone and nothing replaced them: the driver that put Gojo on the borrowed rig, the retarget driver written for models that were not Mixamo-named, and the binding that fastened his clips onto that rig. All three were already unreachable — the first cannot initialise without the bundles, the second is only attached when a model's bones are not Mixamo-named and every shipped model now is, and the third was only called by the first. The one thing anybody still read out of them, the name of Gojo's clip library, now sits beside the other three names in the driver that compares them. Every remaining mention of that character is a comment about how this used to work, and comments do not compile. The four assemblies were then checked, byte by byte, for any spelling of the name: none is left in any of them.
They were doing four jobs, and each has its own answer now. The skeleton and
the humanoid Avatar that translated bone names are replaced by a rig read from
a model file whose bones already carry the names his clips and his outfits ask
for, so there is nothing left to translate. The default body is the formal
suit, taken out of satoru.model with its other outfit dropped so the file
holds exactly one. And the four locomotion clips he was still borrowing —
standing, walking, sprinting and the character-select stance — come from
sukuna.anim, which has always shipped in this package and always had them.
Nothing about him should look different except that he is wearing the suit until a skin is chosen. If something does, it is a bug rather than the intention: this is the same character on his own rig.
The two new outfits stood about two metres out of place. They were rooted
on a bone nothing drives. Every outfit before them is rooted at
mixamorig:Hips, which is the bone the runtime positions against the live rig;
the files taken from the game hang their hips under a root and a jointroot,
and those came through the conversion as the root instead. The hips ended up
1.084 below the rig where they belong 1.084 above it. They are re-rooted at the
hips now, and the converter refuses to write a file it cannot root there.
Two more outfits for Gojo: Day Off and Shirtsleeves. An open khaki overshirt over teal trousers, and a white dress shirt with a belt. Seven skins now, where the five before this were all some shade of black.
These are the first that did not go through an auto-rigger. Every outfit before them arrived as an unrigged mesh and had to be uploaded to Mixamo to get a skeleton; these came already rigged, so the whole step was skipped and their own weights kept — including the bones in the hair and in the shirt hem, which an auto-rig has no way to produce. That is 161 bones against the 52 the older outfits carry, and the hundred-odd extra are exactly the ones nothing drives: they hold the shape they were authored with while the body follows the rig.
Three things had to be measured rather than assumed, and all three are the kind that look right in a screenshot and wrong in motion. Handedness, because a mirrored outfit is a left hand on a right arm and a T-pose hides it. The axis, because these are authored Y-up and everything already working is Z-up. And the bind pose, taken from the file's own inverse bind matrices rather than from its node hierarchy, because the runtime builds its bind poses by inverting the rest it composes and the two have to agree.
A skin whose skeleton is mostly bones nothing drives is no longer rejected. The check that an outfit had resolved enough of its bones to follow the rig asked for half of them, which was right when every file held 52 humanoid bones and all 52 resolved. A 161-bone outfit can only ever resolve 52, so the check threw out a file in which everything that could resolve had. It counts now instead of taking a fraction — what it is guarding against is a rename or a broken skeleton, and that shows up as a handful, not as a proportion.
1.1.6
Gojo animates again when another Sett-based mod is installed. He stood in
the bind pose for the whole run, on every skin, for anyone who also ran a mod
built on the same rig — AoiTodoJJK_Sett is the one this was reported on.
Unity will not open a second asset bundle whose files are already claimed by an
open one, so Gojo's animation bundle never loaded, and the Sett prefab and his
rigged mesh went with it. He now reads those assets out of whichever bundle
already has them, which is where they were all along. The log says so when it
happens instead of leaving an unexplained static model.
Hollow Purple can be built out of Blue and Red. Blue no longer leaves a field on a timer: it stands for up to 8 seconds and drains 15 Cursed Energy a second while it does, closing for 20% damage when it ends or when the pool runs dry. Steer a Red into a field that is still standing and the two cancel — 20% damage, rising to 60% on a full Red charge, across a sphere four times the field's own radius. A tapped Blue makes a 30 metre sphere, a fully charged one makes 116, so how big it is was decided two skills earlier.
Hollow Purple on R remains the bigger single hit at 67.5%, and this is the one
that covers a room. That way round on purpose: the combination is available
about every five seconds and R every thirty, and the frequent thing has to hit
for less than the rare one or the rare one is decoration. It is
drawn the way Hollow Purple draws itself: a shell swelling from the field's
size out to the full radius, the dark sphere inside it, and the shove leaving
after. The log says what it made — field 29.0m -> sphere 116.0m.
A standing Blue field closes on a second press of Mouse5. There was no way to close one on purpose: it ended when its eight seconds ran out, when it had drained the pool dry, or when a Red was steered into it — and Red has to be charged and then flown, which is seconds the field spends energy through. A player who placed it well and wanted it now had to stand and wait.
Handled by the input controller rather than by the skill, because the skill is on cooldown from the moment it is cast and this press has to work while it is.
Red is detonated with the button that cast it. Hold Mouse4 to charge, release to throw, press again to set it off.
Hollow Purple charges faster — 2.5 seconds to the minimum and 4 to the maximum, down from 3.78 and 6. The damage at both ends is unchanged; six seconds of standing still was most of what made it feel unavailable rather than powerful.
Red and Blue both come back in 5 seconds instead of 9, and Red holds two charges. Gojo was not weak, he was idle. Sukuna keeps two skills on no cooldown at all and four more on five, so he is always pressing something; Gojo's cheapest technique was nine, and every one of his is a hold on top of that — up to four seconds on Red, five and a quarter on Blue, four charging Purple.
Counting only what comes off cooldown, this takes him from 0.40 presses a second to 0.58 against Sukuna's 1.46. Still short, and the gap that is left is the two skills Sukuna can press for free rather than anything to do with speed.
The stock is the part that changes how he plays rather than how often. A cooldown alone is a metronome — one press, then a fixed wait, whatever the fight is doing. Two Reds in hand let him answer a moment with both and be empty afterwards, which is the one thing a kit made entirely of holds could not do. The recharge interval is unchanged, so the sustained rate is the same five seconds a Red; only the spending is bursty.
It also frees the Blue-and-Red Hollow Purple, which needs both techniques at once and so sat on a nine second floor no matter what Red did.
Red's cast pose ends when the sphere leaves his hand. The state keeps running after the throw — it has to, so it can fly the orb and watch for the detonator — and the animator was posing the cast for the whole of that. The arm stayed up and the body stayed leaned while the sphere was already across the room on its own, which read as the animation having stuck.
Red's charges are shown on its icon. It gained a second charge and nothing said so — the icon looked the same whether he was holding one or two, and knowing whether you can afford to spend one now is the whole point of stock. The strip has been able to draw this since it was written; it was being handed nothing to draw.
A thrown Red curves gently towards where you are aiming. 95 degrees a second, which over ten metres walks it about a metre sideways and over thirty about fourteen — enough to put one onto something you missed by a little, not enough to turn it round after somebody behind you. Aim where it is already going and it flies straight.
Right click no longer detonates it. It was kept as the binding the skill shipped with, on the reasoning that leaving it cost nothing. It cost the kick: right click is Gojo's secondary, so for as long as a sphere was in the air that button did the wrong one of the two things it means.
A hint panel, on F3. The half-dozen things about each character that a skill description cannot carry — that Hollow Purple is held rather than pressed, that a Red fired into a standing Blue is a different and much larger technique, that a field can be closed early. It sits above the energy bar, shows the lines belonging to whoever you are playing, and F3 toggles it — F2 is the game's own console.
Visible until it is turned off, and then it stays off: a panel behind a key nobody has been told about teaches nobody anything, and one that cannot be dismissed is in the way for everybody after the first run. The toggle writes back to the config, so the second run opens the way the first was left.
Red no longer throws a second sphere when you meant to detonate the first. Giving Red two charges broke it: with one charge the press during a flight found the skill on cooldown and fell through to the detonator by accident, and stock turned that accident into a second Red. A press while one is still live is the detonator now, and only a press with nothing in the air casts.
Gojo regenerates Cursed Energy half again as fast — 2.25 a second at level one against 1.5, and 6.8 at level twenty. Everything added to him this release runs on the pool: a Blue field costs 15 a second simply to stand, both orbs charge out of it, and both now let go the moment it is empty. The combination he was given is also the thing most able to leave him with nothing to press.
Only Gojo. The energy controller sits on all four bodies and had one rate for all of them; the character register now carries the rate per character, which is what it exists for.
An empty pool releases the orb instead of leaving him holding it. Holding Red or Blue was only ever worth anything because it bought overcharge, and with nothing left to buy he stood gripping a sphere that had stopped growing until the four second ceiling ran out. Both now let go the moment the energy is gone.
A Blue that has run out of energy waits two seconds before it closes. The combination empties the pool by design: a field standing costs 15 a second and charging a Red costs more, so setting up the Hollow Purple means spending down to nothing. Closing the field the instant the bar hit zero meant the Blue died first and the Red — which releases when there is nothing left to charge it with — arrived at empty air, so the player who did the whole thing right got a plain Red for it. An exhausted field now stops pulling and stops charging and simply waits to be met.
Flight is a little faster across the ground — 19.5 metres a second at his base speed, up from 17.25. A small step on purpose: flight is the one thing in his kit Sukuna has no answer to, and also the easiest place to overshoot, since too fast means the camera stops keeping up and a stage crosses in a straight line with nothing happening on the way. Climbing and hovering are unchanged.
Gojo hits harder in melee and takes hits better. His combo goes from 2.2 / 2.5 / 5.2 to 2.8 / 3.2 / 6.4, and his armour from 20 to 25. Sukuna swings four times for 14.4 between them where Gojo swung three times for 9.9, and carried 155 health and 30 armour against Gojo's 125 and 20 — so Gojo was paying for being the fragile one twice over, and losing the exchange he was already supposed to lose. His burst was never the problem: a full Hollow Purple is 67.5 against the blade wall's 62.
Still short of Sukuna's melee total on purpose. Gojo is meant to survive an exchange, not win one.
Gojo attacks a fifth faster. Neither character had ever set an attack speed, so both ran at the 1.0 their cloned body came with.
That lands his melee ahead of Sukuna's for the first time — 59.5 a swing-time against 50.4, where before this release it was 39.6 against 50.4. It compounds with the stronger combo above on purpose, but it is now the whole of what was owed: anything further should come off the nuke or the kit, not off the punches.
The Unlimited Void is a dark violet instead of blue. The domain borrowed the colours of the two techniques he throws inside it; it is a place he puts you in, and should not be drawn as one of them. The dome is near-black now and violet only at the rim, the falling light and the far wall stay bright against it, and the barrier comes down in one colour rather than alternating Purple and Blue. The starfield has depth — most stars faint, a few not — because every one of them being equally bright is a pegboard rather than a sky.
Other players can see Sukuna's step again. The stance was gated on the target, and the target is only ever found on the machine that pressed the button — so everyone else in the lobby watched him cross to an enemy standing straight up. The fact is sent now rather than inferred, because a remote machine cannot tell whether the caster found anything, and guessing would put the slash stance on the plain untargeted dash.
Seven of Sukuna's icons and Yuji's kick are redrawn. Two of Sukuna's were drawing each other's technique: Cleave throws two arcs and had a single crescent, Dismantle throws a tight bundle of near-parallel cuts and had the cross. The blade wall showed five upright bars for a technique that lays down a diamond lattice. Fuga's arrow had no head, and the shrine is now the building the domain actually builds. Yuji's kick was three bars and is now a leg.
The Shift no longer writes forty lines to the log per press. 1.1.5 shipped
with the crossing diagnostic switched on. It is now off by default and behind
09 - Main menu в†’ Log the Shift crossing for when a step misbehaves again.
1.1.5
Two fixes to the Shift on both characters.
It could kill you. Used on an enemy below, Gojo's Instant Transmission and Sukuna's step carried you down fast enough that the landing counted as a fall, and from any height it was lethal. Both now ignore fall damage for the length of the dash, and neither leaves you moving downward when it ends.
It circled the enemy instead of arriving. The spot behind them was worked out fresh every frame, and since they turn to face whoever is coming, it rotated away as fast as you chased it — about five laps a second. The spot is now fixed when the skill is pressed and only follows them if they walk. Sukuna also aimed at their chest rather than their feet, so he finished the step hovering a metre up.
1.1.2 — released
Released on Thunderstore.
Satoru Gojo. Steerable Red and Blue orbs, flight, Reversal Red, Instant Transmission, self-healing, Hollow Purple as a charged ultimate, and Unlimited Void. Five skins.
Ryomen Sukuna. A magazine of piercing slashes, the step behind a target, Dismantle, a choice between the Fuga arrow and a wall of blades, and Malevolent Shrine. Three skins.
Both draw on one cursed energy bar that refills on its own and faster on melee hits and kills. A skill you cannot afford does not fire and does not go on cooldown; the pool grows with your level, so the ultimates stay usable at every level.
Keys, Black Flash chance, model scale and the title screen line-up are all configurable, under Mod Options if you have Risk of Options installed.
Notes from before the launch are in CHANGELOG.archive.md in the repository.
Those versions were never on a store page, and the notes are written for
whoever has to maintain this rather than for anyone playing it.