2026-09-21 19:42:31 -07:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "utf-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
2026-09-21 23:43:36 -07:00
< meta name = "color-scheme" content = "dark" >
2026-09-21 19:42:31 -07:00
< title > SOTF Inventory Editor</ title >
< link rel = "icon" href = "data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🌲</text></svg>" >
< link rel = "preconnect" href = "https://fonts.googleapis.com" >
< link rel = "preconnect" href = "https://fonts.gstatic.com" crossorigin >
< link href = "https://fonts.googleapis.com/css2?family=Barlow:wght@400;500;600&family=IM+Fell+English:ital@0;1&display=swap" rel = "stylesheet" >
< link rel = "stylesheet" href = "styles.css" >
</ head >
< body >
< header class = "hero" >
< div class = "hero-inner" >
< h1 > Inventory</ h1 >
< p class = "subtitle" > A save editor for Sons of the Forest. Load your save, set your counts, download the new file.</ p >
</ div >
2026-09-21 23:43:36 -07:00
< svg class = "treeline" aria-hidden = "true" focusable = "false" >
< defs >
< pattern id = "trees" width = "120" height = "90" patternUnits = "userSpaceOnUse" >
< path transform = "scale(1 1.5)" fill = "currentColor" d = "M0 60 L0 44 L8 30 L5 30 L12 16 L9 16 L16 2 L23 16 L20 16 L27 30 L24 30 L32 44 L32 60 Z M30 60 L38 40 L35 40 L42 26 L39 26 L46 14 L53 26 L50 26 L57 40 L54 40 L62 60 Z M58 60 L66 36 L63 36 L71 20 L68 20 L76 6 L84 20 L81 20 L89 36 L86 36 L94 60 Z M90 60 L97 44 L94 44 L101 30 L98 30 L105 20 L112 30 L109 30 L116 44 L113 44 L120 60 Z" />
</ pattern >
</ defs >
< rect width = "100%" height = "100%" fill = "url(#trees)" />
</ svg >
2026-09-21 19:42:31 -07:00
</ header >
< main >
2026-09-21 22:32:53 -07:00
< section class = "loader" id = "dropZone" aria-label = "Load a save file" >
< div class = "loader-head" >
< h2 id = "loaderTitle" > Load your save</ h2 >
2026-09-21 19:42:31 -07:00
< p id = "loaderStatus" > No save loaded. You can browse and edit items, but saving needs a loaded save.</ p >
</ div >
2026-09-21 22:32:53 -07:00
< div class = "options" >
< div class = "option" >
< span class = "option-tag" > Option A</ span >
< h3 > Browse to your file</ h3 >
< p > Your save is here:</ p >
< code class = "path" >< span > %USERPROFILE%\< wbr > AppData\< wbr > LocalLow\< wbr > Endnight\< wbr > SonsOfTheForest\< wbr > Saves\< wbr ></ span >< var > SteamID</ var >< span > \< wbr > SinglePlayer\< wbr ></ span >< var > SaveID</ var >< span > \< wbr > SaveData.zip</ span ></ code >
< p class = "hint" >< var > SteamID</ var > is the long number folder. Pick the newest < var > SaveID</ var > folder. Co-op host saves are in Multiplayer.</ p >
< div class = "option-actions" >
< button type = "button" class = "btn" id = "browseBtn" > Browse</ button >
< button type = "button" class = "btn-link copy-btn" id = "copyPathBtn" >< svg viewBox = "0 0 16 16" width = "13" height = "13" aria-hidden = "true" >< rect x = "5" y = "5" width = "9" height = "9" rx = "1.5" fill = "none" stroke = "currentColor" stroke-width = "1.5" />< path d = "M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" fill = "none" stroke = "currentColor" stroke-width = "1.5" /></ svg >< span > Copy path</ span ></ button >
</ div >
< input type = "file" id = "fileInput" accept = ".zip,.json" hidden >
</ div >
< div class = "option" >
< span class = "option-tag" > Option B</ span >
< h3 > Use this PowerShell script</ h3 >
< p > Close the game, open PowerShell and paste:</ p >
< code class = "path" id = "helperCmd" > irm https://< wbr > raw.githubusercontent.com/< wbr > JustinOros/< wbr > sotf-inventory/< wbr > main/< wbr > Find-SaveData.ps1 | iex</ code >
< p class = "hint" > Explorer opens with your latest SaveData.zip selected. Drag it onto this page.</ p >
< div class = "option-actions" >
< button type = "button" class = "btn copy-btn" id = "copyCmdBtn" >< svg viewBox = "0 0 16 16" width = "13" height = "13" aria-hidden = "true" >< rect x = "5" y = "5" width = "9" height = "9" rx = "1.5" fill = "none" stroke = "currentColor" stroke-width = "1.5" />< path d = "M11 5V3.5A1.5 1.5 0 0 0 9.5 2h-6A1.5 1.5 0 0 0 2 3.5v6A1.5 1.5 0 0 0 3.5 11H5" fill = "none" stroke = "currentColor" stroke-width = "1.5" /></ svg >< span > Copy command</ span ></ button >
</ div >
</ div >
< div class = "option option-drop" id = "dropTarget" tabindex = "0" role = "button" aria-label = "Drop SaveData.zip here or press Enter to browse" >
< span class = "option-tag" > Option C</ span >
< h3 > Drag and drop</ h3 >
< div class = "drop-well" >
< svg viewBox = "0 0 24 24" width = "36" height = "36" aria-hidden = "true" >< path d = "M12 3v12m0 0-4.5-4.5M12 15l4.5-4.5M4 17v2.5A1.5 1.5 0 0 0 5.5 21h13a1.5 1.5 0 0 0 1.5-1.5V17" fill = "none" stroke = "currentColor" stroke-width = "1.6" stroke-linecap = "round" stroke-linejoin = "round" /></ svg >
< span > Drop your SaveData.zip here</ span >
</ div >
2026-09-21 22:07:59 -07:00
</ div >
2026-09-21 19:42:31 -07:00
</ div >
</ section >
< section class = "toolbar" >
< input type = "search" id = "search" placeholder = "Search items by name or ID" autocomplete = "off" aria-label = "Search items" >
< select id = "category" aria-label = "Filter by category" >
< option value = "" > All categories</ option >
</ select >
< label class = "check" >
< input type = "checkbox" id = "ownedOnly" >
< span > Owned only</ span >
</ label >
2026-09-21 23:29:26 -07:00
< label class = "check" >
< input type = "checkbox" id = "changedOnly" >
< span > Changed only</ span >
</ label >
2026-09-21 19:42:31 -07:00
< span class = "count-label" id = "resultCount" ></ span >
</ section >
< div class = "table-wrap" >
< table id = "inventory" >
< thead >
< tr >
< th data-sort = "name" class = "col-name" >< button type = "button" > Item</ button ></ th >
< th data-sort = "category" class = "col-cat" >< button type = "button" > Category</ button ></ th >
< th data-sort = "id" class = "col-id" >< button type = "button" > ID</ button ></ th >
< th data-sort = "count" class = "col-count" >< button type = "button" > Count</ button ></ th >
< th data-sort = "max" class = "col-max" >< button type = "button" > Max</ button ></ th >
</ tr >
</ thead >
< tbody id = "rows" ></ tbody >
</ table >
< p class = "empty" id = "emptyState" hidden > No items match that search. Clear the search or pick another category.</ p >
</ div >
</ main >
< footer class = "savebar" >
< span id = "changeSummary" > No changes</ span >
< div class = "savebar-actions" >
2026-09-21 21:06:07 -07:00
< button type = "button" class = "btn-link" id = "clearBtn" title = "Sets every item to 0 except equipped items and starting tools" > Clear inventory</ button >
2026-09-21 19:42:31 -07:00
< button type = "button" class = "btn-link" id = "resetBtn" disabled > Undo changes</ button >
< button type = "button" class = "btn btn-primary" id = "saveBtn" disabled > Save</ button >
</ div >
</ footer >
< dialog id = "disclaimer" >
< h2 > Close the game first</ h2 >
< p > Quit Sons of the Forest before you edit or replace a save. The game rewrites its save files while running and can overwrite your changes or corrupt the save.</ p >
< p > Unequip items in game before you save and quit. Equipped items are shown here but can't be edited.</ p >
< p > This is a fan tool with no connection to Endnight Games. Your save never leaves your computer.</ p >
< div class = "dialog-actions" >
< button type = "button" class = "btn btn-primary" id = "disclaimerOk" > I understand</ button >
</ div >
</ dialog >
< dialog id = "saveDialog" >
< h2 > Download the new save</ h2 >
< p > You'll get a new < strong id = "saveFileName" > SaveData.zip</ strong > with your changes.</ p >
< p > Keep your original file as a backup. Copy it somewhere safe before you replace it, in case the modified save doesn't load.</ p >
< p > Then put the new file in your save folder, replacing the old one, and start the game.</ p >
< div class = "dialog-actions" >
< button type = "button" class = "btn-link" id = "saveCancel" > Cancel</ button >
< button type = "button" class = "btn btn-primary" id = "saveConfirm" > Download</ button >
</ div >
</ dialog >
< div class = "toast" id = "toast" role = "status" aria-live = "polite" ></ div >
< script src = "https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js" ></ script >
< script src = "items.js" ></ script >
< script src = "app.js" ></ script >
</ body >
</ html >