{"article":{"slug":"explaining-the-magelight-xp-glitch-in-skyrim","title":"Explaining the Magelight XP glitch in Skyrim","subtitle":null,"summary":"A reverse-engineering deep dive into why casting Magelight from a mountain outside Solitude grants huge Alteration XP in Skyrim. It debunks the distance and cloud-layer theories, traces how the projectile's collision and XP grant work in the game code, breaks down the bug, and gives a consistent setup guide to maximise it.","content_type":"blog_post","language":"en","canonical_url":"https://blog.alexbeals.com/posts/explaining-the-magelight-xp-glitch-in-skyrim","author":{"name":"Vox Silva","url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Vox Silva","url":"https://blog.alexbeals.com/","listing_slug":null,"listing":null},"topics":[{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Systems Programming","slug":"systems-programming","url":"https://listedarticles.com/topics/systems-programming"},{"name":"Culture","slug":"culture","url":"https://listedarticles.com/topics/culture"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":2494,"reading_minutes":11,"published_at":"2026-10-06T20:16:39.000Z","added_at":"2026-10-07T11:11:01.188Z","updated_at":"2026-10-07T11:11:01.188Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/explaining-the-magelight-xp-glitch-in-skyrim","markdown_url":"https://listedarticles.com/articles/explaining-the-magelight-xp-glitch-in-skyrim.md","example":false,"citation":"Vox Silva, Vox Silva. \"Explaining the Magelight XP glitch in Skyrim.\" 6 Oct 2026. https://blog.alexbeals.com/posts/explaining-the-magelight-xp-glitch-in-skyrim (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://blog.alexbeals.com/posts/explaining-the-magelight-xp-glitch-in-skyrim"},"body_markdown":"# Explaining the Magelight XP glitch in Skyrim\n\nThere's a place in Skyrim right outside the capital city, Solitude, where if you cast Magelight at the top of a mountain, you get *tons* of XP in Alteration — enough to [level you from 15 to 25](https://www.youtube.com/watch?v=eJU23Wy1EFU) in just one cast. But why?\n\nThere's a lot of wrong explanations for why this works, but the main one is some version based on how far the target is:\n\n\"Magelight grant XP on arrival based on how long it travelled. What you have found is a place where you are on the near edge of render distance, but there are tricks to increase it even further.\" - [@Jewbacca1991](https://www.reddit.com/r/skyrim/comments/11zdiyc/comment/jdc7bme/)\n\n\nBut as [others](https://www.reddit.com/r/skyrim/comments/1wywoga/comment/pe94e6f/) [quickly](https://www.reddit.com/r/skyrim/comments/1bm9rec/comment/kx80dvv/) [point](https://www.reddit.com/r/skyrim/comments/11zdiyc/comment/lv92u1g/) [out](https://www.reddit.com/r/skyrim/comments/11zdiyc/comment/lafv3ab/), it doesn't work for other far distances: something seems to be special about *this* mountain. The [UESP Skyrim wiki](https://en.uesp.net/wiki/Skyrim:Alteration#Magelight:~:text=The%20large%20XP%20gains%20at%20this%20location%20seem%20to%20be%20related%20to%20passing%20through%20multiple%20planes%20of%20weather%20effects) claims that it's because of the cloud layers that you can see:\n\n\"The large XP gains at this location seem to be related to passing through multiple planes of weather effects.\"\n\n\nBut there are plenty of cloudy mountains where this doesn't work. Let's reverse engineer the Magelight XP formula to put this to rest.\n\n## How Magelight grants XP\n\nMagelight is an Apprentice level spell. Loading it up in [TES5Edit](https://www.nexusmods.com/skyrim/mods/25859) we can see that it has a Magnitude of 5, a Duration of 60, and a base effect of `LightFFAimed`, or `0001EA6D`. If we load that effect we can see it has a Base Cost of 2, and a Skill Usage Multiplier of 0.15.\n\nThis all gets used to calculate the Skill Usage value. Because there's no Area for the spell it quickly simplifies:\n\n$$ \\begin{aligned} Skill\\_Usage &= Base\\_Effect\\_Cost \\times Area \\times (Magnitude \\times \\frac{Duration}{10})^{1.1}\\newline &= 2 \\times 1 \\times (5 \\times \\frac{60}{10})^{1.1}\\newline &\\approx 84.307 \\end{aligned} $$\n\nThe Alteration XP takes this, multiplies it by the Skill Usage Multiplier (0.15 for Magelight) and then by the Skill Use Mult ([3 for Alteration](https://en.uesp.net/wiki/Skyrim:Leveling#Skill_XP)) for a raw XP of 37.938 per cast.\n\n### Validating in game\n\nIdeally we'd cast Magelight at a wall and see if this gives the expected amount of XP. Unfortunately there's no way in game (even using console commands) to get the exact XP. Luckily we can use [Cheat Engine](https://www.cheatengine.org/) to read the underlying memory directly with Lua.\n<sup>1</sup>\nYou may remember Lua (my favorite programming language downstream of Brazilian oil companies) from my [previous post speedrunning Harry Potter 1 for the GBA](https://blog.alexbeals.com/posts/harry-potter-anatomy-speedrun#using-lua).\n\n```\n-- (Set the player's Alteration level to 15 with a console command)\n-- player.setav alteration 15\n-- Set the overflow XP to 0\nlocal ALTERATION = 18\nlocal player = readPointer(0x01B2E8E4)\nlocal skills = readPointer(readPointer(player + 0x614))\nlocal entry  = skills + 12 * ALTERATION - 0x40\nwriteFloat(entry + 4, 0)\nprint(string.format('Alteration XP: %.3f', readFloat(entry + 4)))\n-- <Cast the spell>\n-- Read out the current XP\nprint(string.format('Alteration XP: %.3f', readFloat(entry + 4)))\n```\nIf we run the above script\n<sup>2</sup>\nI swapped to using the VEH debugger with \n\nBut none of this incorporates distance. Why are we getting so much more than 38 XP?\n\n## Reverse engineering when the XP grant runs\n\nMagelight is unlike most other spells because it doesn't need to hit a person — it'll work, but it also works to cast it at a wall or a table or a rock. It grants XP in all of these cases, so how does it know when it hits something?\n\n### How collision works\n\nCasting the spell creates a `LightSpellProjectile` that travels along a path based on where you originally aimed it. Each tick it checks if it's collided with something, which roughly follows these three steps:\n\n**Draw a path for where the object will move in the next tick** (`0x007A0090`)\n\nIt takes the speed of the projectile (512 units/s) and divides by your frame rate (60 fps\n<sup>3</sup>\nAnd yes, this means that the collision check rate is lower if you're playing on old Xbox consoles, and higher if you've cranked this above the normal value. It *also* goes higher if you use the [Slow Time shout](https://elderscrolls.fandom.com/wiki/Slow_Time) or use the Archery/Block perks to slow time, though collisions/s stay the same.\n) to get $\\frac{512}{60} = 8.5\\bar{3}$ units/tick in the direction you cast in. The spell has a range of 10,000,\n<sup>4</sup>\nAgain determined by the ESM file, though it wasn't in the above screenshot crop. Whoops.\n so it will continue along its path for $\\approx 19.5$ seconds before it vanishes.\n\n**Intersect that path with every object that has a collision shape and passes the collision layer filtering.** (`0x00DE0040`)  \n\nEvery object in the game has a collision layer which defines what it collides with (for instance `L_TRANSPARENT` won't stop projectiles or spells where `L_TERRAIN` will). If they don't match, a collision won't fire.\n\n**Check if the path hit the object.** (`0x00EC41C0`)  \n\nFirst, it finds the closest point on the surface of the object to the projectile. Then it finds the normal vector that points away from the surface with that closest point.\n\n*Shown here on a rectangular prism, though there are much more complex normal maps for things like rocks or castles*\n\nIt then checks if the projectile is going in the same direction as the normal.\n<sup>5</sup>\nIt does this by checking if the [dot product](https://en.wikipedia.org/wiki/Dot_product#Geometric_definition) is positive or negative. Yay math!\n If they are, it's moving *away* from the surface, so it says there's no collision. If they're moving in opposite directions then it flags a collision if it's already intersecting or inside of the object, or if it will hit it in this next tick step.\n\nNote that even if the projectile is *inside* the object the normal check comes first: if it's made it over halfway through the object, such that the closest point is on the far side and the normal is in the same direction as movement, then it stops triggering collisions.\n\n### What happens when it collides with something\n\nOnce the `LightSpellProjectile` has collided with something (or multiple things) it runs an \"OnHit\" function (`0x007A30FD`) for each collision, triggering what's supposed to happen. The function handles a lot of things that aren't relevant for Magelight\n<sup>6</sup>\nLike [wards](https://en.uesp.net/wiki/Skyrim:Ward) blocking spells at `0x006ECE30` or targets getting knocked back by Destruction spells at `0x006E99D0`.\n but finally either applies the effect to a person\n<sup>7</sup>\nTechnically a magic target, which also includes stuff like activation triggers.\n (`0x00664740`) or the collision surface. Most single-cast spells handle the XP award as part of the person branch, but there's a special check at `0x00660353` that handles giving XP for spells that can handle alternative targets, like Magelight.\n<sup>8</sup>\nActually not *like* Magelight, *just* Magelight. Technically it's all Reanimate and Light spells, but all of the [Reanimate spells](<https://en.uesp.net/wiki/Skyrim:Reanimate_(spells)>) override this location to just grant XP when you raise the body from the dead, and the only other Light spell is [Candlelight](https://en.uesp.net/wiki/Skyrim:Candlelight), which isn't a projectile.\n\nFinally \"OnHit\" adds the impact at `0x007A2560`. It makes sure it only runs once, and checks the material that was hit to run accordingly (attaching to a person, for instance, or just floating near the wall for a wall). If there is no material, or it's an unsupported material, then no impact event happens.\n\n### Stopping the projectile\n\nEverything that's been described so far seems to work, and it mostly does, but here's where it breaks down. After colliding with something and running \"OnHit\" the code runs a \"HandleHit\" function to determine if the projectile should keep going or not. Usually it will stop the projectile, but there are two exemptions: it will keep going if it collides with something 1) non-corporeal\n<sup>9</sup>\nTo be more specific, [`BROAD_PHASE_PHANTOM`](https://geckwiki.com/index.php?title=BhkRigidBody#:~:text=by%20most%20NIFs.-,BROAD_PHASE_PHANTOM,-Used%20by%20NIFs) from Havok's collision code, which is used for triggers (stuff like \"if you walk here activate the trap/cutscene/dialogue\"). This check happens at `0x0079f022`.\n or 2) has the layer type 26 or 28, which corresponds to `L_TRANSPARENT_SMALL` and `L_TRANSPARENT_SMALL_ANIM`.\n<sup>10</sup>\nThis exemption is at `0x0079f063` if you're ~~curious~~ future me looking for proof.\n\n\n`L_TRANSPARENT`, which doesn't collide with `L_SPELL`\n*does*\n\n`L_TRANSPARENT_SMALL`, which *collide with*\n\n`L_PROJECTILE` and `L_SPELL`\nBecause `L_TRANSPARENT_SMALL` 'collides' with projectiles and spells in its collision layer, the surface continually registers collisions without stopping the projectile, leading to the bug.\n\n## The bug breakdown\n\nYou cast Magelight until it enters a bounding box with `L_TRANSPARENT_SMALL`. That collision layer collides with `L_SPELL` so it counts as a collision. It's not a person or magic target, so it hits the fallback path and awards 38 XP. But `L_TRANSPARENT_SMALL` is exempt from the \"HandleHit\" and so the projectile keeps going. Next tick, same thing happens. It's in the bounding box, it counts as a collision, it awards 38 XP. It will keep doing this until the closest point has a normal in the same direction that it's going, which is roughly when it's gone halfway through.\n\nBut where are the `L_TRANSPARENT_SMALL` objects? You guessed it: the mountain right near Solitude.\n<sup>11</sup>\nÏ made the walls visible using a quick mod built off of the [Skyrim Creation Kit](https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/), but you can do the same thing with .esm tweaks to add a debug color for the collision layer.\n\nThere are some other places that have it, like the sides of [High Hrothgar](https://en.uesp.net/wiki/Skyrim:High_Hrothgar):\n\nOr around the statue in [Irkngthand](https://en.uesp.net/wiki/Skyrim:Irkngthand#Irkngthand_Sanctuary) at the conclusion of the Thieves' Guild questline:\n\nOr as very thin planes surrounding the [Thalmor Embassy](https://en.uesp.net/wiki/Skyrim:Thalmor_Embassy):\n\nBut the biggest ones are all next to Solitude, which is why you have to cast at *that mountain*, not just *any* cloudy mountain that's far away.\n\n## How to maximize\n\nMost of the guides say to aim at the top of the mountain, but what you actually want to aim at is whatever line maximizes the amount of time that the spell will be passing through the `L_TRANSPARENT_SMALL` blocks (and in the right sections of them). The mountain is good, but we can do better.\n<sup>12</sup>\nThe top of the mountain gives ~280 triggers vs. ~850 in the optimal place. \n\nÏ quickly\n<sup>13</sup>\nAnd I mean *quickly*, Claude Opus 5.5 two-shot the mod in about 10 minutes with only one screenshot to show what was wrong.\n wrote a mod using [SKSE](https://skse.silverlock.org/) that would render the invisible walls and react to where you were aiming the spell, dynamically calculating the number of expected XP triggers as well as the optimal angle to maximize XP gain. Just walking around the area quickly found the optimal location.\n<sup>14</sup>\nA lot of math also found the 'optimal' location, but it was underground and inaccessible. Ideal.\n\nTo get from Level 15 to Level 100 Alteration you need $\\sum_{L=15}^{99} 2 * L^{1.95}$ = [528,804.0234 XP](https://en.uesp.net/wiki/Skyrim:Leveling#Skill_XP). At 37.938 XP per trigger, that's almost 14,000 triggers, so a line that does 250 triggers vs. 850 triggers is the difference between 55 casts and 17 casts. The key bit, though, is a consistent repro—it's all good to say \"aim at this spot in the sky\" but people can't follow that. So here's a followable guide!\n\n### Consistent setup guide\n\nStart by traveling to Solitude and then exiting the main door, so you're right outside. We're going to want to get up on the rock to the left. There's an invisible wall there, so line up against it and the castle wall in the farthest corner.\n\nWe're going to be aiming at the mortar line of the top left brick of the wall we're pressed up against.\n\nTo get the right angle we're going to **crouch**, and then line up the center of our crosshair with that mortar line (optimal line is the top left corner of the brick one to the right, but there's some leeway).\n\nWe're then going to strafe forward and left so we're pressed up against the invisible wall the whole time, keeping our angle consistent. This will show the two lines of the castle wall from the different pieces.\n\nOur goal is to strafe back until the second line has *just* been hidden again. At this point you should be staring at a seemingly random patch of sky.\n\nCast away!\n<sup>15</sup>\n [I got to level 100 in 17 casts in 1 minute and 15 seconds. If you'd prefer a video walkthrough, I](https://blog.alexbeals.com/images/explaining-the-magelight-xp-glitch-in-skyrim/29.jpg) [uploaded one to YouTube](https://www.youtube.com/watch?v=leJqh3Dzcqo).\n<sup>16</sup>\nI used Claude's computer use for the first time to build in support for the Skyrim-themed UI popups in DaVinci Resolve and watching it work was yet another \"this is magic\" moment. Perfect for one-offs.\n\nWith this, hopefully, *hopefully*, I'm done with Skyrim.\n\n1. \nYou may remember Lua (my favorite programming language downstream of Brazilian oil companies) from my [previous post speedrunning Harry Potter 1 for the GBA](https://blog.alexbeals.com/posts/harry-potter-anatomy-speedrun#using-lua) .[↩︎](https://blog.alexbeals.com#fnref1:lua)\n2. \nI swapped to using the VEH debugger with Edit >Settings >Debugger method , though I'm not sure that's necessary.[↩︎](https://blog.alexbeals.com#fnref1:script)\n3. \nAnd yes, this means that the collision check rate is lower if you're playing on old Xbox consoles, and higher if you've cranked this above the normal value. It *also* goes higher if you use the[Slow Time shout](https://elderscrolls.fandom.com/wiki/Slow_Time) or use the Archery/Block perks to slow time, though collisions/s stay the same.[↩︎](https://blog.alexbeals.com#fnref1:fps)\n4. \nAgain determined by the ESM file, though it wasn't in the above screenshot crop. Whoops. [↩︎](https://blog.alexbeals.com#fnref1:range)\n5. \nIt does this by checking if the [dot product](https://en.wikipedia.org/wiki/Dot_product#Geometric_definition) is positive or negative. Yay math![↩︎](https://blog.alexbeals.com#fnref1:dot)\n6. \nLike [wards](https://en.uesp.net/wiki/Skyrim:Ward) blocking spells at`0x006ECE30` or targets getting knocked back by Destruction spells at`0x006E99D0` .[↩︎](https://blog.alexbeals.com#fnref1:wards)\n7. \nTechnically a magic target, which also includes stuff like activation triggers. [↩︎](https://blog.alexbeals.com#fnref1:person)\n8. \nActually not *like* Magelight,*just* Magelight. Technically it's all Reanimate and Light spells, but all of the[Reanimate spells](<https://en.uesp.net/wiki/Skyrim:Reanimate_(spells)>) override this location to just grant XP when you raise the body from the dead, and the only other Light spell is[Candlelight](https://en.uesp.net/wiki/Skyrim:Candlelight) , which isn't a projectile.[↩︎](https://blog.alexbeals.com#fnref1:reanimate)\n9. \nTo be more specific, [`BROAD_PHASE_PHANTOM`](https://geckwiki.com/index.php?title=BhkRigidBody#:~:text=by%20most%20NIFs.-,BROAD_PHASE_PHANTOM,-Used%20by%20NIFs) from Havok's collision code, which is used for triggers (stuff like \"if you walk here activate the trap/cutscene/dialogue\"). This check happens at`0x0079f022` .[↩︎](https://blog.alexbeals.com#fnref1:phantom)\n10. \nThis exemption is at `0x0079f063` if you're~~curious~~ future me looking for proof.[↩︎](https://blog.alexbeals.com#fnref1:layer)\n11. \nÏ made the walls visible using a quick mod built off of the [Skyrim Creation Kit](https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/) , but you can do the same thing with .esm tweaks to add a debug color for the collision layer.[↩︎](https://blog.alexbeals.com#fnref1:mod)\n12. \nThe top of the mountain gives ~280 triggers vs. ~850 in the optimal place. [↩︎](https://blog.alexbeals.com#fnref1:xp)\n13. \nAnd I mean *quickly* , Claude Opus 5.5 two-shot the mod in about 10 minutes with only one screenshot to show what was wrong.[↩︎](https://blog.alexbeals.com#fnref1:quickly)\n14. \nA lot of math also found the 'optimal' location, but it was underground and inaccessible. Ideal. [↩︎](https://blog.alexbeals.com#fnref1:optimal)\n15. \n[↩︎](https://blog.alexbeals.com#fnref1:cast)\n16. \nI used Claude's computer use for the first time to build in support for the Skyrim-themed UI popups in DaVinci Resolve and watching it work was yet another \"this is magic\" moment. Perfect for one-offs. [↩︎](https://blog.alexbeals.com#fnref1:claude)","body_html":"<h1 id=\"explaining-the-magelight-xp-glitch-in-skyrim\">Explaining the Magelight XP glitch in Skyrim</h1>\n<p>There&#39;s a place in Skyrim right outside the capital city, Solitude, where if you cast Magelight at the top of a mountain, you get <em>tons</em> of XP in Alteration — enough to <a href=\"https://www.youtube.com/watch?v=eJU23Wy1EFU\" rel=\"nofollow ugc noopener\">level you from 15 to 25</a> in just one cast. But why?</p>\n<p>There&#39;s a lot of wrong explanations for why this works, but the main one is some version based on how far the target is:</p>\n<p>&quot;Magelight grant XP on arrival based on how long it travelled. What you have found is a place where you are on the near edge of render distance, but there are tricks to increase it even further.&quot; - <a href=\"https://www.reddit.com/r/skyrim/comments/11zdiyc/comment/jdc7bme/\" rel=\"nofollow ugc noopener\">@Jewbacca1991</a></p>\n<p>But as <a href=\"https://www.reddit.com/r/skyrim/comments/1wywoga/comment/pe94e6f/\" rel=\"nofollow ugc noopener\">others</a> <a href=\"https://www.reddit.com/r/skyrim/comments/1bm9rec/comment/kx80dvv/\" rel=\"nofollow ugc noopener\">quickly</a> <a href=\"https://www.reddit.com/r/skyrim/comments/11zdiyc/comment/lv92u1g/\" rel=\"nofollow ugc noopener\">point</a> <a href=\"https://www.reddit.com/r/skyrim/comments/11zdiyc/comment/lafv3ab/\" rel=\"nofollow ugc noopener\">out</a>, it doesn&#39;t work for other far distances: something seems to be special about <em>this</em> mountain. The <a href=\"https://en.uesp.net/wiki/Skyrim:Alteration#Magelight:~:text=The%20large%20XP%20gains%20at%20this%20location%20seem%20to%20be%20related%20to%20passing%20through%20multiple%20planes%20of%20weather%20effects\" rel=\"nofollow ugc noopener\">UESP Skyrim wiki</a> claims that it&#39;s because of the cloud layers that you can see:</p>\n<p>&quot;The large XP gains at this location seem to be related to passing through multiple planes of weather effects.&quot;</p>\n<p>But there are plenty of cloudy mountains where this doesn&#39;t work. Let&#39;s reverse engineer the Magelight XP formula to put this to rest.</p>\n<h2 id=\"how-magelight-grants-xp\">How Magelight grants XP</h2>\n<p>Magelight is an Apprentice level spell. Loading it up in <a href=\"https://www.nexusmods.com/skyrim/mods/25859\" rel=\"nofollow ugc noopener\">TES5Edit</a> we can see that it has a Magnitude of 5, a Duration of 60, and a base effect of <code>LightFFAimed</code>, or <code>0001EA6D</code>. If we load that effect we can see it has a Base Cost of 2, and a Skill Usage Multiplier of 0.15.</p>\n<p>This all gets used to calculate the Skill Usage value. Because there&#39;s no Area for the spell it quickly simplifies:</p>\n<p>$$ \\begin{aligned} Skill_Usage &amp;= Base_Effect_Cost \\times Area \\times (Magnitude \\times \\frac{Duration}{10})^{1.1}\\newline &amp;= 2 \\times 1 \\times (5 \\times \\frac{60}{10})^{1.1}\\newline &amp;\\approx 84.307 \\end{aligned} $$</p>\n<p>The Alteration XP takes this, multiplies it by the Skill Usage Multiplier (0.15 for Magelight) and then by the Skill Use Mult (<a href=\"https://en.uesp.net/wiki/Skyrim:Leveling#Skill_XP\" rel=\"nofollow ugc noopener\">3 for Alteration</a>) for a raw XP of 37.938 per cast.</p>\n<h3 id=\"validating-in-game\">Validating in game</h3>\n<p>Ideally we&#39;d cast Magelight at a wall and see if this gives the expected amount of XP. Unfortunately there&#39;s no way in game (even using console commands) to get the exact XP. Luckily we can use <a href=\"https://www.cheatengine.org/\" rel=\"nofollow ugc noopener\">Cheat Engine</a> to read the underlying memory directly with Lua.\n&lt;sup&gt;1&lt;/sup&gt;\nYou may remember Lua (my favorite programming language downstream of Brazilian oil companies) from my <a href=\"https://blog.alexbeals.com/posts/harry-potter-anatomy-speedrun#using-lua\" rel=\"nofollow ugc noopener\">previous post speedrunning Harry Potter 1 for the GBA</a>.</p>\n<pre><code>-- (Set the player&#39;s Alteration level to 15 with a console command)\n-- player.setav alteration 15\n-- Set the overflow XP to 0\nlocal ALTERATION = 18\nlocal player = readPointer(0x01B2E8E4)\nlocal skills = readPointer(readPointer(player + 0x614))\nlocal entry  = skills + 12 * ALTERATION - 0x40\nwriteFloat(entry + 4, 0)\nprint(string.format(&#39;Alteration XP: %.3f&#39;, readFloat(entry + 4)))\n-- &lt;Cast the spell&gt;\n-- Read out the current XP\nprint(string.format(&#39;Alteration XP: %.3f&#39;, readFloat(entry + 4)))</code></pre>\n<p>If we run the above script\n&lt;sup&gt;2&lt;/sup&gt;\nI swapped to using the VEH debugger with </p>\n<p>But none of this incorporates distance. Why are we getting so much more than 38 XP?</p>\n<h2 id=\"reverse-engineering-when-the-xp-grant-runs\">Reverse engineering when the XP grant runs</h2>\n<p>Magelight is unlike most other spells because it doesn&#39;t need to hit a person — it&#39;ll work, but it also works to cast it at a wall or a table or a rock. It grants XP in all of these cases, so how does it know when it hits something?</p>\n<h3 id=\"how-collision-works\">How collision works</h3>\n<p>Casting the spell creates a <code>LightSpellProjectile</code> that travels along a path based on where you originally aimed it. Each tick it checks if it&#39;s collided with something, which roughly follows these three steps:</p>\n<p><strong>Draw a path for where the object will move in the next tick</strong> (<code>0x007A0090</code>)</p>\n<p>It takes the speed of the projectile (512 units/s) and divides by your frame rate (60 fps\n&lt;sup&gt;3&lt;/sup&gt;\nAnd yes, this means that the collision check rate is lower if you&#39;re playing on old Xbox consoles, and higher if you&#39;ve cranked this above the normal value. It <em>also</em> goes higher if you use the <a href=\"https://elderscrolls.fandom.com/wiki/Slow_Time\" rel=\"nofollow ugc noopener\">Slow Time shout</a> or use the Archery/Block perks to slow time, though collisions/s stay the same.\n) to get $\\frac{512}{60} = 8.5\\bar{3}$ units/tick in the direction you cast in. The spell has a range of 10,000,\n&lt;sup&gt;4&lt;/sup&gt;\nAgain determined by the ESM file, though it wasn&#39;t in the above screenshot crop. Whoops.\n so it will continue along its path for $\\approx 19.5$ seconds before it vanishes.</p>\n<p><strong>Intersect that path with every object that has a collision shape and passes the collision layer filtering.</strong> (<code>0x00DE0040</code>)  </p>\n<p>Every object in the game has a collision layer which defines what it collides with (for instance <code>L_TRANSPARENT</code> won&#39;t stop projectiles or spells where <code>L_TERRAIN</code> will). If they don&#39;t match, a collision won&#39;t fire.</p>\n<p><strong>Check if the path hit the object.</strong> (<code>0x00EC41C0</code>)  </p>\n<p>First, it finds the closest point on the surface of the object to the projectile. Then it finds the normal vector that points away from the surface with that closest point.</p>\n<p><em>Shown here on a rectangular prism, though there are much more complex normal maps for things like rocks or castles</em></p>\n<p>It then checks if the projectile is going in the same direction as the normal.\n&lt;sup&gt;5&lt;/sup&gt;\nIt does this by checking if the <a href=\"https://en.wikipedia.org/wiki/Dot_product#Geometric_definition\" rel=\"nofollow ugc noopener\">dot product</a> is positive or negative. Yay math!\n If they are, it&#39;s moving <em>away</em> from the surface, so it says there&#39;s no collision. If they&#39;re moving in opposite directions then it flags a collision if it&#39;s already intersecting or inside of the object, or if it will hit it in this next tick step.</p>\n<p>Note that even if the projectile is <em>inside</em> the object the normal check comes first: if it&#39;s made it over halfway through the object, such that the closest point is on the far side and the normal is in the same direction as movement, then it stops triggering collisions.</p>\n<h3 id=\"what-happens-when-it-collides-with-something\">What happens when it collides with something</h3>\n<p>Once the <code>LightSpellProjectile</code> has collided with something (or multiple things) it runs an &quot;OnHit&quot; function (<code>0x007A30FD</code>) for each collision, triggering what&#39;s supposed to happen. The function handles a lot of things that aren&#39;t relevant for Magelight\n&lt;sup&gt;6&lt;/sup&gt;\nLike <a href=\"https://en.uesp.net/wiki/Skyrim:Ward\" rel=\"nofollow ugc noopener\">wards</a> blocking spells at <code>0x006ECE30</code> or targets getting knocked back by Destruction spells at <code>0x006E99D0</code>.\n but finally either applies the effect to a person\n&lt;sup&gt;7&lt;/sup&gt;\nTechnically a magic target, which also includes stuff like activation triggers.\n (<code>0x00664740</code>) or the collision surface. Most single-cast spells handle the XP award as part of the person branch, but there&#39;s a special check at <code>0x00660353</code> that handles giving XP for spells that can handle alternative targets, like Magelight.\n&lt;sup&gt;8&lt;/sup&gt;\nActually not <em>like</em> Magelight, <em>just</em> Magelight. Technically it&#39;s all Reanimate and Light spells, but all of the <a href=\"https://en.uesp.net/wiki/Skyrim:Reanimate_(spells)\" rel=\"nofollow ugc noopener\">Reanimate spells</a> override this location to just grant XP when you raise the body from the dead, and the only other Light spell is <a href=\"https://en.uesp.net/wiki/Skyrim:Candlelight\" rel=\"nofollow ugc noopener\">Candlelight</a>, which isn&#39;t a projectile.</p>\n<p>Finally &quot;OnHit&quot; adds the impact at <code>0x007A2560</code>. It makes sure it only runs once, and checks the material that was hit to run accordingly (attaching to a person, for instance, or just floating near the wall for a wall). If there is no material, or it&#39;s an unsupported material, then no impact event happens.</p>\n<h3 id=\"stopping-the-projectile\">Stopping the projectile</h3>\n<p>Everything that&#39;s been described so far seems to work, and it mostly does, but here&#39;s where it breaks down. After colliding with something and running &quot;OnHit&quot; the code runs a &quot;HandleHit&quot; function to determine if the projectile should keep going or not. Usually it will stop the projectile, but there are two exemptions: it will keep going if it collides with something 1) non-corporeal\n&lt;sup&gt;9&lt;/sup&gt;\nTo be more specific, <a href=\"https://geckwiki.com/index.php?title=BhkRigidBody#:~:text=by%20most%20NIFs.-,BROAD_PHASE_PHANTOM,-Used%20by%20NIFs\" rel=\"nofollow ugc noopener\"><code>BROAD_PHASE_PHANTOM</code></a> from Havok&#39;s collision code, which is used for triggers (stuff like &quot;if you walk here activate the trap/cutscene/dialogue&quot;). This check happens at <code>0x0079f022</code>.\n or 2) has the layer type 26 or 28, which corresponds to <code>L_TRANSPARENT_SMALL</code> and <code>L_TRANSPARENT_SMALL_ANIM</code>.\n&lt;sup&gt;10&lt;/sup&gt;\nThis exemption is at <code>0x0079f063</code> if you&#39;re <del>curious</del> future me looking for proof.</p>\n<p><code>L_TRANSPARENT</code>, which doesn&#39;t collide with <code>L_SPELL</code>\n<em>does</em></p>\n<p><code>L_TRANSPARENT_SMALL</code>, which <em>collide with</em></p>\n<p><code>L_PROJECTILE</code> and <code>L_SPELL</code>\nBecause <code>L_TRANSPARENT_SMALL</code> &#39;collides&#39; with projectiles and spells in its collision layer, the surface continually registers collisions without stopping the projectile, leading to the bug.</p>\n<h2 id=\"the-bug-breakdown\">The bug breakdown</h2>\n<p>You cast Magelight until it enters a bounding box with <code>L_TRANSPARENT_SMALL</code>. That collision layer collides with <code>L_SPELL</code> so it counts as a collision. It&#39;s not a person or magic target, so it hits the fallback path and awards 38 XP. But <code>L_TRANSPARENT_SMALL</code> is exempt from the &quot;HandleHit&quot; and so the projectile keeps going. Next tick, same thing happens. It&#39;s in the bounding box, it counts as a collision, it awards 38 XP. It will keep doing this until the closest point has a normal in the same direction that it&#39;s going, which is roughly when it&#39;s gone halfway through.</p>\n<p>But where are the <code>L_TRANSPARENT_SMALL</code> objects? You guessed it: the mountain right near Solitude.\n&lt;sup&gt;11&lt;/sup&gt;\nÏ made the walls visible using a quick mod built off of the <a href=\"https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/\" rel=\"nofollow ugc noopener\">Skyrim Creation Kit</a>, but you can do the same thing with .esm tweaks to add a debug color for the collision layer.</p>\n<p>There are some other places that have it, like the sides of <a href=\"https://en.uesp.net/wiki/Skyrim:High_Hrothgar\" rel=\"nofollow ugc noopener\">High Hrothgar</a>:</p>\n<p>Or around the statue in <a href=\"https://en.uesp.net/wiki/Skyrim:Irkngthand#Irkngthand_Sanctuary\" rel=\"nofollow ugc noopener\">Irkngthand</a> at the conclusion of the Thieves&#39; Guild questline:</p>\n<p>Or as very thin planes surrounding the <a href=\"https://en.uesp.net/wiki/Skyrim:Thalmor_Embassy\" rel=\"nofollow ugc noopener\">Thalmor Embassy</a>:</p>\n<p>But the biggest ones are all next to Solitude, which is why you have to cast at <em>that mountain</em>, not just <em>any</em> cloudy mountain that&#39;s far away.</p>\n<h2 id=\"how-to-maximize\">How to maximize</h2>\n<p>Most of the guides say to aim at the top of the mountain, but what you actually want to aim at is whatever line maximizes the amount of time that the spell will be passing through the <code>L_TRANSPARENT_SMALL</code> blocks (and in the right sections of them). The mountain is good, but we can do better.\n&lt;sup&gt;12&lt;/sup&gt;\nThe top of the mountain gives ~280 triggers vs. ~850 in the optimal place. </p>\n<p>Ï quickly\n&lt;sup&gt;13&lt;/sup&gt;\nAnd I mean <em>quickly</em>, Claude Opus 5.5 two-shot the mod in about 10 minutes with only one screenshot to show what was wrong.\n wrote a mod using <a href=\"https://skse.silverlock.org/\" rel=\"nofollow ugc noopener\">SKSE</a> that would render the invisible walls and react to where you were aiming the spell, dynamically calculating the number of expected XP triggers as well as the optimal angle to maximize XP gain. Just walking around the area quickly found the optimal location.\n&lt;sup&gt;14&lt;/sup&gt;\nA lot of math also found the &#39;optimal&#39; location, but it was underground and inaccessible. Ideal.</p>\n<p>To get from Level 15 to Level 100 Alteration you need $\\sum_{L=15}^{99} 2 * L^{1.95}$ = <a href=\"https://en.uesp.net/wiki/Skyrim:Leveling#Skill_XP\" rel=\"nofollow ugc noopener\">528,804.0234 XP</a>. At 37.938 XP per trigger, that&#39;s almost 14,000 triggers, so a line that does 250 triggers vs. 850 triggers is the difference between 55 casts and 17 casts. The key bit, though, is a consistent repro—it&#39;s all good to say &quot;aim at this spot in the sky&quot; but people can&#39;t follow that. So here&#39;s a followable guide!</p>\n<h3 id=\"consistent-setup-guide\">Consistent setup guide</h3>\n<p>Start by traveling to Solitude and then exiting the main door, so you&#39;re right outside. We&#39;re going to want to get up on the rock to the left. There&#39;s an invisible wall there, so line up against it and the castle wall in the farthest corner.</p>\n<p>We&#39;re going to be aiming at the mortar line of the top left brick of the wall we&#39;re pressed up against.</p>\n<p>To get the right angle we&#39;re going to <strong>crouch</strong>, and then line up the center of our crosshair with that mortar line (optimal line is the top left corner of the brick one to the right, but there&#39;s some leeway).</p>\n<p>We&#39;re then going to strafe forward and left so we&#39;re pressed up against the invisible wall the whole time, keeping our angle consistent. This will show the two lines of the castle wall from the different pieces.</p>\n<p>Our goal is to strafe back until the second line has <em>just</em> been hidden again. At this point you should be staring at a seemingly random patch of sky.</p>\n<p>Cast away!\n&lt;sup&gt;15&lt;/sup&gt;\n <a href=\"https://blog.alexbeals.com/images/explaining-the-magelight-xp-glitch-in-skyrim/29.jpg\" rel=\"nofollow ugc noopener\">I got to level 100 in 17 casts in 1 minute and 15 seconds. If you&#39;d prefer a video walkthrough, I</a> <a href=\"https://www.youtube.com/watch?v=leJqh3Dzcqo\" rel=\"nofollow ugc noopener\">uploaded one to YouTube</a>.\n&lt;sup&gt;16&lt;/sup&gt;\nI used Claude&#39;s computer use for the first time to build in support for the Skyrim-themed UI popups in DaVinci Resolve and watching it work was yet another &quot;this is magic&quot; moment. Perfect for one-offs.</p>\n<p>With this, hopefully, <em>hopefully</em>, I&#39;m done with Skyrim.</p>\n<ol><li></li></ol>\n<p>You may remember Lua (my favorite programming language downstream of Brazilian oil companies) from my <a href=\"https://blog.alexbeals.com/posts/harry-potter-anatomy-speedrun#using-lua\" rel=\"nofollow ugc noopener\">previous post speedrunning Harry Potter 1 for the GBA</a> .<a href=\"https://blog.alexbeals.com#fnref1:lua\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"2\"><li></li></ol>\n<p>I swapped to using the VEH debugger with Edit &gt;Settings &gt;Debugger method , though I&#39;m not sure that&#39;s necessary.<a href=\"https://blog.alexbeals.com#fnref1:script\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"3\"><li></li></ol>\n<p>And yes, this means that the collision check rate is lower if you&#39;re playing on old Xbox consoles, and higher if you&#39;ve cranked this above the normal value. It <em>also</em> goes higher if you use the<a href=\"https://elderscrolls.fandom.com/wiki/Slow_Time\" rel=\"nofollow ugc noopener\">Slow Time shout</a> or use the Archery/Block perks to slow time, though collisions/s stay the same.<a href=\"https://blog.alexbeals.com#fnref1:fps\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"4\"><li></li></ol>\n<p>Again determined by the ESM file, though it wasn&#39;t in the above screenshot crop. Whoops. <a href=\"https://blog.alexbeals.com#fnref1:range\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"5\"><li></li></ol>\n<p>It does this by checking if the <a href=\"https://en.wikipedia.org/wiki/Dot_product#Geometric_definition\" rel=\"nofollow ugc noopener\">dot product</a> is positive or negative. Yay math<img src=\"https://blog.alexbeals.com#fnref1:dot\" alt=\"↩︎\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></p>\n<ol start=\"6\"><li></li></ol>\n<p>Like <a href=\"https://en.uesp.net/wiki/Skyrim:Ward\" rel=\"nofollow ugc noopener\">wards</a> blocking spells at<code>0x006ECE30</code> or targets getting knocked back by Destruction spells at<code>0x006E99D0</code> .<a href=\"https://blog.alexbeals.com#fnref1:wards\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"7\"><li></li></ol>\n<p>Technically a magic target, which also includes stuff like activation triggers. <a href=\"https://blog.alexbeals.com#fnref1:person\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"8\"><li></li></ol>\n<p>Actually not <em>like</em> Magelight,<em>just</em> Magelight. Technically it&#39;s all Reanimate and Light spells, but all of the<a href=\"https://en.uesp.net/wiki/Skyrim:Reanimate_(spells)\" rel=\"nofollow ugc noopener\">Reanimate spells</a> override this location to just grant XP when you raise the body from the dead, and the only other Light spell is<a href=\"https://en.uesp.net/wiki/Skyrim:Candlelight\" rel=\"nofollow ugc noopener\">Candlelight</a> , which isn&#39;t a projectile.<a href=\"https://blog.alexbeals.com#fnref1:reanimate\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"9\"><li></li></ol>\n<p>To be more specific, <a href=\"https://geckwiki.com/index.php?title=BhkRigidBody#:~:text=by%20most%20NIFs.-,BROAD_PHASE_PHANTOM,-Used%20by%20NIFs\" rel=\"nofollow ugc noopener\"><code>BROAD_PHASE_PHANTOM</code></a> from Havok&#39;s collision code, which is used for triggers (stuff like &quot;if you walk here activate the trap/cutscene/dialogue&quot;). This check happens at<code>0x0079f022</code> .<a href=\"https://blog.alexbeals.com#fnref1:phantom\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"10\"><li></li></ol>\n<p>This exemption is at <code>0x0079f063</code> if you&#39;re<del>curious</del> future me looking for proof.<a href=\"https://blog.alexbeals.com#fnref1:layer\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"11\"><li></li></ol>\n<p>Ï made the walls visible using a quick mod built off of the <a href=\"https://store.steampowered.com/app/1946180/Skyrim_Special_Edition_Creation_Kit/\" rel=\"nofollow ugc noopener\">Skyrim Creation Kit</a> , but you can do the same thing with .esm tweaks to add a debug color for the collision layer.<a href=\"https://blog.alexbeals.com#fnref1:mod\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"12\"><li></li></ol>\n<p>The top of the mountain gives ~280 triggers vs. ~850 in the optimal place. <a href=\"https://blog.alexbeals.com#fnref1:xp\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"13\"><li></li></ol>\n<p>And I mean <em>quickly</em> , Claude Opus 5.5 two-shot the mod in about 10 minutes with only one screenshot to show what was wrong.<a href=\"https://blog.alexbeals.com#fnref1:quickly\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"14\"><li></li></ol>\n<p>A lot of math also found the &#39;optimal&#39; location, but it was underground and inaccessible. Ideal. <a href=\"https://blog.alexbeals.com#fnref1:optimal\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"15\"><li></li></ol>\n<p><a href=\"https://blog.alexbeals.com#fnref1:cast\" rel=\"nofollow ugc noopener\">↩︎</a></p>\n<ol start=\"16\"><li></li></ol>\n<p>I used Claude&#39;s computer use for the first time to build in support for the Skyrim-themed UI popups in DaVinci Resolve and watching it work was yet another &quot;this is magic&quot; moment. Perfect for one-offs. <a href=\"https://blog.alexbeals.com#fnref1:claude\" rel=\"nofollow ugc noopener\">↩︎</a></p>","headings":[{"level":1,"text":"Explaining the Magelight XP glitch in Skyrim","id":"explaining-the-magelight-xp-glitch-in-skyrim"},{"level":2,"text":"How Magelight grants XP","id":"how-magelight-grants-xp"},{"level":3,"text":"Validating in game","id":"validating-in-game"},{"level":2,"text":"Reverse engineering when the XP grant runs","id":"reverse-engineering-when-the-xp-grant-runs"},{"level":3,"text":"How collision works","id":"how-collision-works"},{"level":3,"text":"What happens when it collides with something","id":"what-happens-when-it-collides-with-something"},{"level":3,"text":"Stopping the projectile","id":"stopping-the-projectile"},{"level":2,"text":"The bug breakdown","id":"the-bug-breakdown"},{"level":2,"text":"How to maximize","id":"how-to-maximize"},{"level":3,"text":"Consistent setup guide","id":"consistent-setup-guide"}]}}