modwright 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +35 -0
- package/README.md +212 -0
- package/assets/claude/agents/mw-explore.md +46 -0
- package/assets/claude/agents/mw-fixture.md +33 -0
- package/assets/claude/agents/mw-rule-author.md +51 -0
- package/assets/claude/agents/mw-scaffold-author.md +48 -0
- package/assets/claude/skills/mw-author.md +59 -0
- package/assets/claude/skills/mw-new-item.md +51 -0
- package/assets/claude/skills/mw-new-spell.md +50 -0
- package/assets/claude/skills/mw-scaffold.md +59 -0
- package/assets/claude/skills/mw-ship.md +57 -0
- package/assets/claude/skills/mw-validate.md +51 -0
- package/assets/claude/skills/mw-verify.md +59 -0
- package/assets/nivalisnights/extract_resources.py +177 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Config.json +5 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapClient.lua +55 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/BootstrapServer.lua +81 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Log.lua +96 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Probes.lua +1038 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/ProbesClient.lua +74 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Protocol.lua +985 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/ScriptExtender/Lua/ModWrightBridge/Watch.lua +175 -0
- package/bridges/bg3-se/Mods/ModWrightBridge/meta.lsx +45 -0
- package/bridges/bg3-se/README.md +99 -0
- package/bridges/bg3-se/bridge.json +68 -0
- package/bridges/cp2077-cet/ModWrightBridge/init.lua +375 -0
- package/bridges/cp2077-cet/ModWrightBridge/probes.lua +1104 -0
- package/bridges/cp2077-cet/ModWrightBridge/protocol.lua +1306 -0
- package/bridges/cp2077-cet/README.md +165 -0
- package/bridges/cp2077-cet/bridge.json +53 -0
- package/dist/core/bridge/arm.js +175 -0
- package/dist/core/bridge/cet-console.js +26 -0
- package/dist/core/bridge/cet-log.js +362 -0
- package/dist/core/bridge/index.js +11 -0
- package/dist/core/bridge/locate.js +35 -0
- package/dist/core/bridge/paths.js +34 -0
- package/dist/core/bridge/pending.js +89 -0
- package/dist/core/bridge/poll.js +155 -0
- package/dist/core/bridge/stage.js +100 -0
- package/dist/core/bridge/status.js +97 -0
- package/dist/core/bridge/types.js +145 -0
- package/dist/core/bridge/validate.js +107 -0
- package/dist/core/build/index.js +6 -0
- package/dist/core/build/manifest.js +47 -0
- package/dist/core/build/paths.js +32 -0
- package/dist/core/build/run.js +342 -0
- package/dist/core/build/stage.js +265 -0
- package/dist/core/build/steps/bg3.js +129 -0
- package/dist/core/build/steps/core.js +195 -0
- package/dist/core/build/steps/cyberpunk.js +95 -0
- package/dist/core/build/steps/listing.js +35 -0
- package/dist/core/build/types.js +13 -0
- package/dist/core/build/zip.js +148 -0
- package/dist/core/compat/check.js +113 -0
- package/dist/core/compat/pe.js +220 -0
- package/dist/core/compat/types.js +1 -0
- package/dist/core/compat/version.js +70 -0
- package/dist/core/deploy/guards.js +292 -0
- package/dist/core/deploy/index.js +5 -0
- package/dist/core/deploy/plan.js +696 -0
- package/dist/core/deploy/reload-apply.js +361 -0
- package/dist/core/deploy/reload.js +358 -0
- package/dist/core/deploy/sources.js +169 -0
- package/dist/core/deploy/types.js +1 -0
- package/dist/core/epic.js +54 -0
- package/dist/core/fsutil.js +191 -0
- package/dist/core/home.js +70 -0
- package/dist/core/knowledge/facts.js +229 -0
- package/dist/core/knowledge/index.js +4 -0
- package/dist/core/knowledge/search.js +112 -0
- package/dist/core/knowledge/store.js +123 -0
- package/dist/core/knowledge/types.js +1 -0
- package/dist/core/ledger/check.js +42 -0
- package/dist/core/ledger/hooks.js +80 -0
- package/dist/core/ledger/index.js +7 -0
- package/dist/core/ledger/query.js +17 -0
- package/dist/core/ledger/record.js +84 -0
- package/dist/core/ledger/status.js +53 -0
- package/dist/core/ledger/store.js +98 -0
- package/dist/core/ledger/types.js +108 -0
- package/dist/core/logs/index.js +4 -0
- package/dist/core/logs/registry.js +50 -0
- package/dist/core/logs/scan.js +195 -0
- package/dist/core/logs/triage.js +160 -0
- package/dist/core/logs/types.js +1 -0
- package/dist/core/lsx.js +10 -0
- package/dist/core/lz4.js +66 -0
- package/dist/core/mods.js +229 -0
- package/dist/core/process.js +49 -0
- package/dist/core/project/build-steps.js +83 -0
- package/dist/core/project/describe.js +74 -0
- package/dist/core/project/index.js +5 -0
- package/dist/core/project/load.js +146 -0
- package/dist/core/project/schema.js +264 -0
- package/dist/core/project/types.js +3 -0
- package/dist/core/prompts.js +72 -0
- package/dist/core/registry.js +35 -0
- package/dist/core/safety/backup.js +206 -0
- package/dist/core/safety/execute.js +188 -0
- package/dist/core/safety/index.js +5 -0
- package/dist/core/safety/plan.js +122 -0
- package/dist/core/safety/restore.js +172 -0
- package/dist/core/safety/types.js +1 -0
- package/dist/core/scaffold/bootstrap.js +7 -0
- package/dist/core/scaffold/catalog.js +28 -0
- package/dist/core/scaffold/claude-assets.js +271 -0
- package/dist/core/scaffold/collisions.js +64 -0
- package/dist/core/scaffold/emit.js +356 -0
- package/dist/core/scaffold/engine.js +680 -0
- package/dist/core/scaffold/ids.js +78 -0
- package/dist/core/scaffold/index.js +10 -0
- package/dist/core/scaffold/jsonpath.js +121 -0
- package/dist/core/scaffold/load.js +81 -0
- package/dist/core/scaffold/render.js +85 -0
- package/dist/core/scaffold/sequence.js +396 -0
- package/dist/core/scaffold/types.js +309 -0
- package/dist/core/steam.js +63 -0
- package/dist/core/surfaceutil.js +36 -0
- package/dist/core/testplan/check.js +67 -0
- package/dist/core/testplan/index.js +5 -0
- package/dist/core/testplan/load.js +100 -0
- package/dist/core/testplan/registry.js +317 -0
- package/dist/core/testplan/run.js +389 -0
- package/dist/core/testplan/types.js +82 -0
- package/dist/core/text/converters/bg3.js +50 -0
- package/dist/core/text/converters/cyberpunk.js +36 -0
- package/dist/core/text/converters/index.js +261 -0
- package/dist/core/text/diff/cr2w.js +180 -0
- package/dist/core/text/diff/index.js +16 -0
- package/dist/core/text/diff/loca.js +43 -0
- package/dist/core/text/diff/lsx.js +126 -0
- package/dist/core/text/handles.js +86 -0
- package/dist/core/text/index.js +6 -0
- package/dist/core/text/json.js +46 -0
- package/dist/core/text/templates/cache.js +71 -0
- package/dist/core/text/templates/index.js +3 -0
- package/dist/core/text/templates/library.js +245 -0
- package/dist/core/text/templates/types.js +51 -0
- package/dist/core/text/toolchain.js +16 -0
- package/dist/core/text/types.js +1 -0
- package/dist/core/text/validate.js +149 -0
- package/dist/core/text/xml.js +58 -0
- package/dist/core/toolchain/datafetch.js +151 -0
- package/dist/core/toolchain/env.js +63 -0
- package/dist/core/toolchain/features.js +170 -0
- package/dist/core/toolchain/index.js +8 -0
- package/dist/core/toolchain/install.js +191 -0
- package/dist/core/toolchain/locate.js +275 -0
- package/dist/core/toolchain/remember.js +84 -0
- package/dist/core/toolchain/run.js +318 -0
- package/dist/core/toolchain/specs.js +351 -0
- package/dist/core/toolchain/types.js +1 -0
- package/dist/core/types.js +1 -0
- package/dist/core/userconfig.js +66 -0
- package/dist/core/validate/context.js +139 -0
- package/dist/core/validate/index.js +5 -0
- package/dist/core/validate/registry.js +58 -0
- package/dist/core/validate/run.js +131 -0
- package/dist/core/validate/suppressions.js +91 -0
- package/dist/core/validate/types.js +2 -0
- package/dist/core/yamledit.js +51 -0
- package/dist/index.js +389 -0
- package/dist/server.js +1914 -0
- package/dist/surfaces/baldursgate3/compat.js +164 -0
- package/dist/surfaces/baldursgate3/identity.js +110 -0
- package/dist/surfaces/baldursgate3/index/build.js +331 -0
- package/dist/surfaces/baldursgate3/index/index.js +17 -0
- package/dist/surfaces/baldursgate3/index/info.js +40 -0
- package/dist/surfaces/baldursgate3/index/parsers/loca.js +41 -0
- package/dist/surfaces/baldursgate3/index/parsers/lsx.js +137 -0
- package/dist/surfaces/baldursgate3/index/parsers/stats.js +45 -0
- package/dist/surfaces/baldursgate3/index/parsers/treasuretable.js +57 -0
- package/dist/surfaces/baldursgate3/index/parsers/xmlutil.js +142 -0
- package/dist/surfaces/baldursgate3/index/queries.js +327 -0
- package/dist/surfaces/baldursgate3/index/schema.js +62 -0
- package/dist/surfaces/baldursgate3/index.js +3 -0
- package/dist/surfaces/baldursgate3/logs.js +278 -0
- package/dist/surfaces/baldursgate3/modsettings.js +115 -0
- package/dist/surfaces/baldursgate3/pak.js +153 -0
- package/dist/surfaces/baldursgate3/settings.js +49 -0
- package/dist/surfaces/baldursgate3/surface.js +232 -0
- package/dist/surfaces/baldursgate3/validators/bridge.js +7 -0
- package/dist/surfaces/baldursgate3/validators/files.js +476 -0
- package/dist/surfaces/baldursgate3/validators/items.js +1001 -0
- package/dist/surfaces/baldursgate3/validators/progression.js +734 -0
- package/dist/surfaces/baldursgate3/validators/stats.js +1076 -0
- package/dist/surfaces/baldursgate3/validators/story.js +790 -0
- package/dist/surfaces/baldursgate3/validators/templates.js +7 -0
- package/dist/surfaces/cyberpunk2077/compat.js +223 -0
- package/dist/surfaces/cyberpunk2077/index/build.js +231 -0
- package/dist/surfaces/cyberpunk2077/index/index.js +17 -0
- package/dist/surfaces/cyberpunk2077/index/info.js +51 -0
- package/dist/surfaces/cyberpunk2077/index/model.js +52 -0
- package/dist/surfaces/cyberpunk2077/index/parsers/tweak.js +483 -0
- package/dist/surfaces/cyberpunk2077/index/parsers/tweakxl-yaml.js +183 -0
- package/dist/surfaces/cyberpunk2077/index/queries.js +504 -0
- package/dist/surfaces/cyberpunk2077/index/resource.js +135 -0
- package/dist/surfaces/cyberpunk2077/index/schema.js +90 -0
- package/dist/surfaces/cyberpunk2077/index.js +3 -0
- package/dist/surfaces/cyberpunk2077/logs.js +742 -0
- package/dist/surfaces/cyberpunk2077/paths.js +12 -0
- package/dist/surfaces/cyberpunk2077/surface.js +218 -0
- package/dist/surfaces/cyberpunk2077/validators/bridge.js +7 -0
- package/dist/surfaces/cyberpunk2077/validators/cr2w.js +349 -0
- package/dist/surfaces/cyberpunk2077/validators/garments.js +1181 -0
- package/dist/surfaces/cyberpunk2077/validators/mesh.js +338 -0
- package/dist/surfaces/cyberpunk2077/validators/modsettings.js +120 -0
- package/dist/surfaces/cyberpunk2077/validators/packaging.js +463 -0
- package/dist/surfaces/cyberpunk2077/validators/red4ext.js +318 -0
- package/dist/surfaces/cyberpunk2077/validators/redscript.js +193 -0
- package/dist/surfaces/cyberpunk2077/validators/templates.js +7 -0
- package/dist/surfaces/cyberpunk2077/validators/tweaks.js +768 -0
- package/dist/surfaces/cyberpunk2077/validators/vehicles.js +531 -0
- package/dist/surfaces/cyberpunk2077/validators/xl.js +308 -0
- package/dist/surfaces/eldenring/binders.js +111 -0
- package/dist/surfaces/eldenring/compat.js +166 -0
- package/dist/surfaces/eldenring/dcx.js +49 -0
- package/dist/surfaces/eldenring/index.js +13 -0
- package/dist/surfaces/eldenring/loaders.js +132 -0
- package/dist/surfaces/eldenring/logs.js +67 -0
- package/dist/surfaces/eldenring/paramdef.js +256 -0
- package/dist/surfaces/eldenring/params.js +129 -0
- package/dist/surfaces/eldenring/surface.js +121 -0
- package/dist/surfaces/eldenring/tools.js +52 -0
- package/dist/surfaces/eldenring/validators/binders.js +193 -0
- package/dist/surfaces/eldenring/validators/packages.js +159 -0
- package/dist/surfaces/eldenring/validators/params.js +334 -0
- package/dist/surfaces/eldenring/validators/profiles.js +287 -0
- package/dist/surfaces/index.js +34 -0
- package/dist/surfaces/nivalisnights/compat.js +229 -0
- package/dist/surfaces/nivalisnights/index/build.js +310 -0
- package/dist/surfaces/nivalisnights/index/index.js +5 -0
- package/dist/surfaces/nivalisnights/index/queries.js +231 -0
- package/dist/surfaces/nivalisnights/index.js +4 -0
- package/dist/surfaces/nivalisnights/logs.js +473 -0
- package/dist/surfaces/nivalisnights/surface.js +195 -0
- package/dist/surfaces/skyrimse/archives.js +229 -0
- package/dist/surfaces/skyrimse/compat.js +163 -0
- package/dist/surfaces/skyrimse/index.js +12 -0
- package/dist/surfaces/skyrimse/loadorder.js +174 -0
- package/dist/surfaces/skyrimse/logs.js +241 -0
- package/dist/surfaces/skyrimse/plugins.js +149 -0
- package/dist/surfaces/skyrimse/records.js +94 -0
- package/dist/surfaces/skyrimse/surface.js +240 -0
- package/dist/surfaces/skyrimse/validators/archive-records.js +165 -0
- package/dist/surfaces/skyrimse/validators/archives.js +110 -0
- package/dist/surfaces/skyrimse/validators/plugins.js +374 -0
- package/dist/surfaces/skyrimse/validators/records.js +117 -0
- package/dist/surfaces/stardewvalley/compat.js +190 -0
- package/dist/surfaces/stardewvalley/config.js +42 -0
- package/dist/surfaces/stardewvalley/contentpatcher.js +203 -0
- package/dist/surfaces/stardewvalley/index/index.js +229 -0
- package/dist/surfaces/stardewvalley/index/wiki.js +190 -0
- package/dist/surfaces/stardewvalley/index.js +12 -0
- package/dist/surfaces/stardewvalley/logs.js +307 -0
- package/dist/surfaces/stardewvalley/mods.js +182 -0
- package/dist/surfaces/stardewvalley/surface.js +244 -0
- package/dist/surfaces/stardewvalley/validators/content.js +321 -0
- package/dist/surfaces/stardewvalley/validators/fields.js +147 -0
- package/dist/surfaces/stardewvalley/validators/loadorder.js +69 -0
- package/dist/surfaces/stardewvalley/validators/manifest.js +221 -0
- package/dist/surfaces/subnautica2/compat.js +138 -0
- package/dist/surfaces/subnautica2/index.js +5 -0
- package/dist/surfaces/subnautica2/logs.js +129 -0
- package/dist/surfaces/subnautica2/paks.js +173 -0
- package/dist/surfaces/subnautica2/surface.js +151 -0
- package/dist/surfaces/subnautica2/validators/packaging.js +298 -0
- package/dist/surfaces/valheim/compat.js +171 -0
- package/dist/surfaces/valheim/index/index.js +301 -0
- package/dist/surfaces/valheim/index/tables.js +103 -0
- package/dist/surfaces/valheim/index.js +11 -0
- package/dist/surfaces/valheim/logs.js +197 -0
- package/dist/surfaces/valheim/packaging.js +131 -0
- package/dist/surfaces/valheim/plugins.js +270 -0
- package/dist/surfaces/valheim/references.js +121 -0
- package/dist/surfaces/valheim/surface.js +223 -0
- package/dist/surfaces/valheim/validators/packaging.js +218 -0
- package/dist/surfaces/valheim/validators/plugins.js +287 -0
- package/dist/surfaces/valheim/validators/references.js +169 -0
- package/knowledge/baldursgate3/animations.gr2.yaml +166 -0
- package/knowledge/baldursgate3/audio.voice.yaml +182 -0
- package/knowledge/baldursgate3/audio.wwise.yaml +104 -0
- package/knowledge/baldursgate3/charactercreation.heads-hair.yaml +193 -0
- package/knowledge/baldursgate3/communitylibrary.shared-content.yaml +129 -0
- package/knowledge/baldursgate3/compatibilityframework.api.yaml +176 -0
- package/knowledge/baldursgate3/crash.causes.yaml +90 -0
- package/knowledge/baldursgate3/dialogue.dialogbank.yaml +120 -0
- package/knowledge/baldursgate3/dialogue.files.yaml +236 -0
- package/knowledge/baldursgate3/dialogue.osiris-goals.yaml +386 -0
- package/knowledge/baldursgate3/dialogue.yaml +122 -0
- package/knowledge/baldursgate3/feats.classes.yaml +164 -0
- package/knowledge/baldursgate3/items.cloth-physics.yaml +167 -0
- package/knowledge/baldursgate3/items.roottemplates.yaml +320 -0
- package/knowledge/baldursgate3/items.visualbank.yaml +628 -0
- package/knowledge/baldursgate3/journal.quests.yaml +214 -0
- package/knowledge/baldursgate3/loadorder.modsettings.yaml +128 -0
- package/knowledge/baldursgate3/localization.handles.yaml +92 -0
- package/knowledge/baldursgate3/misc.encoding-and-practice.yaml +111 -0
- package/knowledge/baldursgate3/origins.companions.yaml +144 -0
- package/knowledge/baldursgate3/osiris.signatures.yaml +211 -0
- package/knowledge/baldursgate3/packaging.meta.yaml +155 -0
- package/knowledge/baldursgate3/packaging.paks.yaml +79 -0
- package/knowledge/baldursgate3/process.launch.yaml +34 -0
- package/knowledge/baldursgate3/progressions.yaml +92 -0
- package/knowledge/baldursgate3/publishing.modio-nexus.yaml +170 -0
- package/knowledge/baldursgate3/publishing.toolkit-modio.yaml +135 -0
- package/knowledge/baldursgate3/races.progression.yaml +228 -0
- package/knowledge/baldursgate3/scriptextender.console.yaml +257 -0
- package/knowledge/baldursgate3/scriptextender.yaml +252 -0
- package/knowledge/baldursgate3/stats.boosts.yaml +293 -0
- package/knowledge/baldursgate3/stats.equipment-kits.yaml +69 -0
- package/knowledge/baldursgate3/stats.interrupts.yaml +45 -0
- package/knowledge/baldursgate3/stats.itemcombos.yaml +65 -0
- package/knowledge/baldursgate3/stats.spells.yaml +293 -0
- package/knowledge/baldursgate3/stats.weapons.yaml +210 -0
- package/knowledge/baldursgate3/toolchain.divine.yaml +179 -0
- package/knowledge/baldursgate3/toolchain.lslib-formats.yaml +242 -0
- package/knowledge/baldursgate3/toolkit.levels.yaml +177 -0
- package/knowledge/baldursgate3/ui.icons-atlas.yaml +78 -0
- package/knowledge/baldursgate3/ui.icons.yaml +412 -0
- package/knowledge/baldursgate3/ui.mcm.yaml +161 -0
- package/knowledge/baldursgate3/vfx.materials.yaml +174 -0
- package/knowledge/baldursgate3/visuals.characterfix.yaml +73 -0
- package/knowledge/cyberpunk2077/animations.anims.yaml +118 -0
- package/knowledge/cyberpunk2077/anims.archivexl.yaml +163 -0
- package/knowledge/cyberpunk2077/anims.authoring.yaml +579 -0
- package/knowledge/cyberpunk2077/anims.encoder.yaml +156 -0
- package/knowledge/cyberpunk2077/anims.graph.yaml +629 -0
- package/knowledge/cyberpunk2077/anims.method.yaml +360 -0
- package/knowledge/cyberpunk2077/anims.pipeline.yaml +352 -0
- package/knowledge/cyberpunk2077/anims.roundtrip.yaml +222 -0
- package/knowledge/cyberpunk2077/anims.sets.yaml +176 -0
- package/knowledge/cyberpunk2077/archivexl.bodytypes.yaml +149 -0
- package/knowledge/cyberpunk2077/archivexl.dynamic-appearances.yaml +218 -0
- package/knowledge/cyberpunk2077/archivexl.manifest.yaml +214 -0
- package/knowledge/cyberpunk2077/audio.events.yaml +168 -0
- package/knowledge/cyberpunk2077/audio.sounds.yaml +164 -0
- package/knowledge/cyberpunk2077/audio.voicesets.yaml +146 -0
- package/knowledge/cyberpunk2077/cet.sandbox.yaml +219 -0
- package/knowledge/cyberpunk2077/clothing.garments.yaml +283 -0
- package/knowledge/cyberpunk2077/clothing.refits.yaml +215 -0
- package/knowledge/cyberpunk2077/codeware.overview.yaml +111 -0
- package/knowledge/cyberpunk2077/codeware.systems.yaml +192 -0
- package/knowledge/cyberpunk2077/drones.combat.yaml +416 -0
- package/knowledge/cyberpunk2077/drones.control.yaml +552 -0
- package/knowledge/cyberpunk2077/entities.appearance.yaml +166 -0
- package/knowledge/cyberpunk2077/equipmentex.slots.yaml +151 -0
- package/knowledge/cyberpunk2077/fx.effects.yaml +246 -0
- package/knowledge/cyberpunk2077/fx.lights.yaml +171 -0
- package/knowledge/cyberpunk2077/hair.modding.yaml +145 -0
- package/knowledge/cyberpunk2077/items.wiring.yaml +246 -0
- package/knowledge/cyberpunk2077/loadorder.archives.yaml +71 -0
- package/knowledge/cyberpunk2077/mesh.blender.yaml +209 -0
- package/knowledge/cyberpunk2077/nativedb.dump.yaml +98 -0
- package/knowledge/cyberpunk2077/npc.appearance.yaml +275 -0
- package/knowledge/cyberpunk2077/npc.behaviour.yaml +128 -0
- package/knowledge/cyberpunk2077/npc.locomotion.yaml +490 -0
- package/knowledge/cyberpunk2077/packaging.deploy.yaml +175 -0
- package/knowledge/cyberpunk2077/packaging.variants.yaml +176 -0
- package/knowledge/cyberpunk2077/player.control.yaml +918 -0
- package/knowledge/cyberpunk2077/process.assetbuild.yaml +154 -0
- package/knowledge/cyberpunk2077/process.lessons.yaml +276 -0
- package/knowledge/cyberpunk2077/quests.minor.yaml +46 -0
- package/knowledge/cyberpunk2077/quests.scenes.yaml +282 -0
- package/knowledge/cyberpunk2077/quickhacks.tiers.yaml +41 -0
- package/knowledge/cyberpunk2077/red4ext.api.yaml +645 -0
- package/knowledge/cyberpunk2077/red4ext.plugins.yaml +124 -0
- package/knowledge/cyberpunk2077/redhottools.hotreload.yaml +245 -0
- package/knowledge/cyberpunk2077/redscript.compile-log.yaml +76 -0
- package/knowledge/cyberpunk2077/redscript.modules.yaml +118 -0
- package/knowledge/cyberpunk2077/toolchain.wolvenkit.yaml +163 -0
- package/knowledge/cyberpunk2077/tweakdb.loot-recipes.yaml +184 -0
- package/knowledge/cyberpunk2077/tweakdb.melee.yaml +352 -0
- package/knowledge/cyberpunk2077/tweakdb.weapons.yaml +325 -0
- package/knowledge/cyberpunk2077/tweakxl.hotreload.yaml +151 -0
- package/knowledge/cyberpunk2077/tweakxl.yaml-syntax.yaml +208 -0
- package/knowledge/cyberpunk2077/ui.icons.yaml +259 -0
- package/knowledge/cyberpunk2077/ui.inkatlas.yaml +81 -0
- package/knowledge/cyberpunk2077/ui.modsettings.yaml +204 -0
- package/knowledge/cyberpunk2077/vehicles.control.yaml +475 -0
- package/knowledge/cyberpunk2077/vehicles.dashboard-ui.yaml +203 -0
- package/knowledge/cyberpunk2077/vehicles.entities.yaml +195 -0
- package/knowledge/cyberpunk2077/vehicles.wiring.yaml +137 -0
- package/knowledge/cyberpunk2077/wolvenkit.cli.yaml +167 -0
- package/knowledge/cyberpunk2077/workspot.system.yaml +55 -0
- package/knowledge/cyberpunk2077/world.interactions.yaml +41 -0
- package/knowledge/cyberpunk2077/world.loot-container.yaml +167 -0
- package/knowledge/cyberpunk2077/world.sectors.yaml +233 -0
- package/knowledge/eldenring/formats.binders.yaml +237 -0
- package/knowledge/eldenring/launcher.me3.yaml +230 -0
- package/knowledge/eldenring/launcher.modengine2.yaml +119 -0
- package/knowledge/eldenring/params.paramdef.yaml +149 -0
- package/knowledge/eldenring/params.regulation.yaml +142 -0
- package/knowledge/eldenring/saves.online.yaml +118 -0
- package/knowledge/eldenring/toolchain.cli.yaml +256 -0
- package/knowledge/nivalisnights/modding.runtime.yaml +157 -0
- package/knowledge/skyrimse/archives.bsa.yaml +212 -0
- package/knowledge/skyrimse/install.detection.yaml +41 -0
- package/knowledge/skyrimse/loadorder.files.yaml +242 -0
- package/knowledge/skyrimse/plugins.esl.yaml +189 -0
- package/knowledge/skyrimse/plugins.format.yaml +224 -0
- package/knowledge/skyrimse/skse.runtime.yaml +283 -0
- package/knowledge/skyrimse/toolchain.xedit-spriggit.yaml +336 -0
- package/knowledge/stardewvalley/contentpatcher.format.yaml +338 -0
- package/knowledge/stardewvalley/distribution.channels.yaml +236 -0
- package/knowledge/stardewvalley/game.versions.yaml +202 -0
- package/knowledge/stardewvalley/install.layout.yaml +277 -0
- package/knowledge/stardewvalley/smapi.loader.yaml +284 -0
- package/knowledge/stardewvalley/smapi.logs.yaml +329 -0
- package/knowledge/stardewvalley/smapi.manifest.yaml +293 -0
- package/knowledge/stardewvalley/toolchain.build.yaml +261 -0
- package/knowledge/stardewvalley/wiki.dataformat.yaml +130 -0
- package/knowledge/subnautica2/game.build.yaml +331 -0
- package/knowledge/subnautica2/modding.state.yaml +210 -0
- package/knowledge/subnautica2/ue5.containers.yaml +72 -0
- package/knowledge/subnautica2/ue5.paks.yaml +203 -0
- package/knowledge/subnautica2/ue5.tooling.yaml +175 -0
- package/knowledge/subnautica2/ue5.ue4ss.yaml +203 -0
- package/knowledge/valheim/bepinex.loader.yaml +247 -0
- package/knowledge/valheim/bepinex.plugins.yaml +251 -0
- package/knowledge/valheim/game.versions.yaml +321 -0
- package/knowledge/valheim/install.layout.yaml +216 -0
- package/knowledge/valheim/jotunn.library.yaml +334 -0
- package/knowledge/valheim/thunderstore.packaging.yaml +217 -0
- package/knowledge/valheim/toolchain.build.yaml +111 -0
- package/package.json +29 -0
- package/scaffolds/baldursgate3/new-class-injection.yaml +148 -0
- package/scaffolds/baldursgate3/new-item.yaml +264 -0
- package/scaffolds/baldursgate3/new-mod.yaml +174 -0
- package/scaffolds/baldursgate3/new-passive.yaml +100 -0
- package/scaffolds/baldursgate3/new-project.yaml +118 -0
- package/scaffolds/baldursgate3/new-quest-stub.yaml +159 -0
- package/scaffolds/baldursgate3/new-spell.yaml +102 -0
- package/scaffolds/baldursgate3/new-status.yaml +119 -0
- package/scaffolds/baldursgate3/sequences/subclass-kit.yaml +50 -0
- package/scaffolds/cyberpunk2077/edit-tweak.yaml +70 -0
- package/scaffolds/cyberpunk2077/mesh-export-preset.yaml +170 -0
- package/scaffolds/cyberpunk2077/new-entity-patch.yaml +255 -0
- package/scaffolds/cyberpunk2077/new-garment-refit.yaml +279 -0
- package/scaffolds/cyberpunk2077/new-item-chain.yaml +548 -0
- package/scaffolds/cyberpunk2077/new-localization.yaml +130 -0
- package/scaffolds/cyberpunk2077/new-mod-settings.yaml +133 -0
- package/scaffolds/cyberpunk2077/new-player-replacer.yaml +1003 -0
- package/scaffolds/cyberpunk2077/new-project.yaml +157 -0
- package/scaffolds/cyberpunk2077/new-sector-node.yaml +156 -0
- package/scaffolds/cyberpunk2077/new-tweak.yaml +121 -0
- package/scaffolds/cyberpunk2077/new-vehicle-livery.yaml +148 -0
- package/scaffolds/cyberpunk2077/new-workspot-entity.yaml +177 -0
- package/scaffolds/cyberpunk2077/sequences/iconic-weapon.yaml +72 -0
- package/scaffolds/cyberpunk2077/sequences/quickhack-takeover.yaml +213 -0
- package/scaffolds/stardewvalley/new-cp-patch.yaml +106 -0
- package/scaffolds/stardewvalley/new-csharp-mod.yaml +195 -0
- package/scaffolds/stardewvalley/new-project.yaml +184 -0
- package/scaffolds/stardewvalley/sequences/content-pack.yaml +31 -0
- package/scripts/mw-tool.mjs +184 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# new-quest-stub (BG3). A
|
|
2
|
+
# flat (non-nested) goal: INIT sets a DB fact, KB reacts to it with a
|
|
3
|
+
# QuestUpdate into a fresh top-level journal quest, EXIT clears the fact.
|
|
4
|
+
#
|
|
5
|
+
# Scope note: a full quest stub would also include
|
|
6
|
+
# "one dialogue greeting node". A real dialogue node is a Story
|
|
7
|
+
# Editor-authored .lsj that ships as the binary-derived intermediate of a
|
|
8
|
+
# vanilla DialogsBinary .lsf (bg3.story.dialogue-source-version's own
|
|
9
|
+
# appliesTo comment) — there is no plain-text authoring convention for it at
|
|
10
|
+
# all, and producing one needs the `divine` toolchain this scaffold's
|
|
11
|
+
# `needs` deliberately does not require. This scaffold stops at the goal,
|
|
12
|
+
# the journal and a Flags/<uuid>.lsx stub; wiring an actual dialogue node is
|
|
13
|
+
# left to the manual checklist below, as with other creative work.
|
|
14
|
+
id: baldursgate3.new-quest-stub
|
|
15
|
+
game: baldursgate3
|
|
16
|
+
title: New BG3 quest stub (goal + journal)
|
|
17
|
+
summary: Write a flat Osiris goal (INIT/KB/EXIT) that QuestUpdates a fresh top-level journal quest, plus a Flags/<uuid>.lsx stub and loca rows.
|
|
18
|
+
modTypes: [quest, dialogue]
|
|
19
|
+
needs: { index: true }
|
|
20
|
+
inputs:
|
|
21
|
+
- type: string
|
|
22
|
+
name: goalName
|
|
23
|
+
prompt: "Goal file name, Act_Region_Situation convention (e.g. Act1_Riverside_MyQuestIntro)."
|
|
24
|
+
pattern: "^[A-Za-z0-9]+(_[A-Za-z0-9]+){2,}$"
|
|
25
|
+
- type: string
|
|
26
|
+
name: journalTitle
|
|
27
|
+
prompt: "Journal quest category display text."
|
|
28
|
+
- type: string
|
|
29
|
+
name: firstEntryText
|
|
30
|
+
prompt: "First journal entry display text."
|
|
31
|
+
ids:
|
|
32
|
+
- name: questId
|
|
33
|
+
slot: "${project.identity.folder}_${input.goalName}_Quest"
|
|
34
|
+
form: map-key
|
|
35
|
+
- name: entryId
|
|
36
|
+
slot: "${project.identity.folder}_${input.goalName}_Start"
|
|
37
|
+
form: map-key
|
|
38
|
+
- name: startedDb
|
|
39
|
+
slot: "DB_${project.identity.folder}_${input.goalName}_Started"
|
|
40
|
+
form: map-key
|
|
41
|
+
- name: flagUuid
|
|
42
|
+
slot: "flag:${input.goalName}"
|
|
43
|
+
form: uuid
|
|
44
|
+
- name: journalTitleHandle
|
|
45
|
+
slot: "journal-title:${input.goalName}"
|
|
46
|
+
form: bg3-handle
|
|
47
|
+
- name: journalEntryHandle
|
|
48
|
+
slot: "journal-entry:${input.goalName}"
|
|
49
|
+
form: bg3-handle
|
|
50
|
+
emits:
|
|
51
|
+
# Under Mods/<folder>/Story/... — a mod's Story tree ships inside its own
|
|
52
|
+
# module folder (like meta.lsx and ScriptExtender), not at the project
|
|
53
|
+
# root, and has to sit under a declared project source for `validate` to
|
|
54
|
+
# ever look at it at all (`listFiles()` only walks declared sources).
|
|
55
|
+
- op: ensure-dir
|
|
56
|
+
path: "Mods/${project.identity.folder}/Story/RawFiles/Goals"
|
|
57
|
+
- op: ensure-dir
|
|
58
|
+
path: "Mods/${project.identity.folder}/Story/Journals"
|
|
59
|
+
- op: ensure-dir
|
|
60
|
+
path: "Public/${project.identity.folder}/Flags"
|
|
61
|
+
- op: write-text
|
|
62
|
+
path: "Mods/${project.identity.folder}/Story/RawFiles/Goals/${input.goalName}.txt"
|
|
63
|
+
body: |
|
|
64
|
+
INIT
|
|
65
|
+
${ids.startedDb}(1)
|
|
66
|
+
|
|
67
|
+
KB
|
|
68
|
+
IF
|
|
69
|
+
${ids.startedDb}(_)
|
|
70
|
+
THEN
|
|
71
|
+
QuestUpdate("${ids.questId}","${ids.entryId}")
|
|
72
|
+
|
|
73
|
+
EXIT
|
|
74
|
+
SysClear(${ids.startedDb})
|
|
75
|
+
- op: write-text
|
|
76
|
+
path: "Mods/${project.identity.folder}/Story/Journals/${input.goalName}.lsx"
|
|
77
|
+
body: |
|
|
78
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
79
|
+
<save>
|
|
80
|
+
<version major="4" minor="0" revision="9" build="200" />
|
|
81
|
+
<region id="Journal">
|
|
82
|
+
<node id="JournalRoot">
|
|
83
|
+
<children>
|
|
84
|
+
<node id="Category">
|
|
85
|
+
<attribute id="Name" type="FixedString" value="${ids.questId}" />
|
|
86
|
+
<attribute id="DisplayName" type="TranslatedString" handle="${ids.journalTitleHandle}" version="1" />
|
|
87
|
+
<children>
|
|
88
|
+
<node id="Entry">
|
|
89
|
+
<attribute id="ID" type="FixedString" value="${ids.entryId}" />
|
|
90
|
+
<attribute id="Text" type="TranslatedString" handle="${ids.journalEntryHandle}" version="1" />
|
|
91
|
+
</node>
|
|
92
|
+
</children>
|
|
93
|
+
</node>
|
|
94
|
+
</children>
|
|
95
|
+
</node>
|
|
96
|
+
</region>
|
|
97
|
+
</save>
|
|
98
|
+
- op: write-text
|
|
99
|
+
path: "Public/${project.identity.folder}/Flags/${ids.flagUuid}.lsx"
|
|
100
|
+
body: |
|
|
101
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
102
|
+
<save>
|
|
103
|
+
<version major="4" minor="0" revision="9" build="200" />
|
|
104
|
+
<region id="Flag">
|
|
105
|
+
<node id="Flag">
|
|
106
|
+
<attribute id="UUID" type="FixedString" value="${ids.flagUuid}" />
|
|
107
|
+
</node>
|
|
108
|
+
</region>
|
|
109
|
+
</save>
|
|
110
|
+
- op: insert-loca-row
|
|
111
|
+
path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
|
|
112
|
+
handle: "${ids.journalTitleHandle}"
|
|
113
|
+
text: "${input.journalTitle}"
|
|
114
|
+
- op: insert-loca-row
|
|
115
|
+
path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
|
|
116
|
+
handle: "${ids.journalEntryHandle}"
|
|
117
|
+
text: "${input.firstEntryText}"
|
|
118
|
+
templates: []
|
|
119
|
+
satisfies:
|
|
120
|
+
- bg3.story.osiris-section-structure
|
|
121
|
+
- bg3.story.osiris-naming-convention
|
|
122
|
+
- bg3.story.osiris-symbol-defined
|
|
123
|
+
- bg3.story.goal-parent-completes
|
|
124
|
+
- bg3.story.questupdate-parent-id
|
|
125
|
+
- bg3.story.quest-entry-exists
|
|
126
|
+
- bg3.story.questadd-questclose-discouraged
|
|
127
|
+
# Not listed: bg3.story.dialogue-flag-guid-resolves. It needs a dialogue
|
|
128
|
+
# .lsj that references the flag, which this scaffold leaves to the manual
|
|
129
|
+
# step, so on a real project it only ever skipped and the apply reported
|
|
130
|
+
# unclean (observed in game 2026-09-11).
|
|
131
|
+
- bg3.history.handle-defined-in-loca
|
|
132
|
+
manual:
|
|
133
|
+
- title: Wire the dialogue and trigger
|
|
134
|
+
steps:
|
|
135
|
+
- "Author the actual dialogue greeting node in the Story Editor and repoint its DialogBank SourceFile per the namespaced pattern."
|
|
136
|
+
- "Fire ${ids.startedDb}(1) from whichever trigger (an interaction, a region trigger) should start this quest."
|
|
137
|
+
- "Confirm the Flags/${ids.flagUuid}.lsx UUID is referenced from the dialogue node that should set it."
|
|
138
|
+
expected: "The trigger sets the DB fact, the goal's KB rule fires QuestUpdate, and the journal shows the new entry."
|
|
139
|
+
claim:
|
|
140
|
+
idSuffix: fires
|
|
141
|
+
claim: "Triggering ${ids.startedDb} completes the ${input.goalName} goal's KB rule and unlocks the ${ids.entryId} journal entry."
|
|
142
|
+
testRows:
|
|
143
|
+
- gate: G-1
|
|
144
|
+
title: "Goal DB fact and journal entry"
|
|
145
|
+
# bg3.event.watch/bg3.osiris.health are attested kinds, but both need an
|
|
146
|
+
# armed observe window straddling the manual trigger step above (fire
|
|
147
|
+
# ${ids.startedDb} from whichever interaction/region trigger a human
|
|
148
|
+
# wires up) — there is no scaffold-time input to arm ahead of a human
|
|
149
|
+
# action that has not happened yet, so this stays a manual row: a person
|
|
150
|
+
# arms both probes, fires the trigger, then reads the results by hand.
|
|
151
|
+
expected: "A human arms bg3.event.watch/bg3.osiris.health, fires the trigger, and confirms ${ids.startedDb} fired with no Osiris degradation."
|
|
152
|
+
manual: true
|
|
153
|
+
probeKinds: [bg3.event.watch, bg3.osiris.health]
|
|
154
|
+
- gate: G-2
|
|
155
|
+
title: "Dialogue and journal review"
|
|
156
|
+
expected: "The authored dialogue node fires and the journal query shows the entry unlocked."
|
|
157
|
+
manual: true
|
|
158
|
+
probeKinds: []
|
|
159
|
+
evidence: ["ModWright research"]
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# new-spell (BG3). Appends one "new entry" block to Spell_<Type>.txt after a
|
|
2
|
+
# dated rationale comment and two loca rows for DisplayName/Description. No SpellAnimation is
|
|
3
|
+
# written — the parent (via `using`) is expected to supply one, as is
|
|
4
|
+
# usual for a Target-type spell inheriting from a vanilla parent.
|
|
5
|
+
id: baldursgate3.new-spell
|
|
6
|
+
game: baldursgate3
|
|
7
|
+
title: New BG3 spell (SpellData entry)
|
|
8
|
+
summary: Append a SpellData entry to Spell_<Type>.txt with a vanilla `using` parent, plus DisplayName/Description loca rows.
|
|
9
|
+
modTypes: [dialogue]
|
|
10
|
+
needs: { index: true }
|
|
11
|
+
inputs:
|
|
12
|
+
- type: string
|
|
13
|
+
name: entryName
|
|
14
|
+
prompt: "Full stats entry name, e.g. MyMod_ShortCircuit."
|
|
15
|
+
pattern: "^[A-Za-z][A-Za-z0-9_]*$"
|
|
16
|
+
- type: enum
|
|
17
|
+
name: spellType
|
|
18
|
+
prompt: "SpellType (also names the Spell_<Type>.txt file)."
|
|
19
|
+
values: [Target, Projectile, Shout]
|
|
20
|
+
- type: index-ref
|
|
21
|
+
name: parent
|
|
22
|
+
prompt: "Vanilla (or project) SpellData entry to `using`."
|
|
23
|
+
lookup: { kind: stat, params: { name: "${input.parent}" } }
|
|
24
|
+
requires:
|
|
25
|
+
- path: type
|
|
26
|
+
matches: "^SpellData$"
|
|
27
|
+
reason: "the parent must be a SpellData entry, or `using` inherits fields from the wrong stat family."
|
|
28
|
+
- type: string
|
|
29
|
+
name: level
|
|
30
|
+
prompt: "Spell level (0 for cantrip)."
|
|
31
|
+
default: "1"
|
|
32
|
+
- type: string
|
|
33
|
+
name: displayName
|
|
34
|
+
prompt: "Player-facing spell name."
|
|
35
|
+
- type: string
|
|
36
|
+
name: description
|
|
37
|
+
prompt: "Tooltip description text."
|
|
38
|
+
ids:
|
|
39
|
+
- name: display
|
|
40
|
+
slot: "display:${input.entryName}"
|
|
41
|
+
form: bg3-handle
|
|
42
|
+
- name: description
|
|
43
|
+
slot: "description:${input.entryName}"
|
|
44
|
+
form: bg3-handle
|
|
45
|
+
emits:
|
|
46
|
+
- op: insert-block
|
|
47
|
+
path: "Public/${project.identity.folder}/Stats/Generated/Data/Spell_${input.spellType}.txt"
|
|
48
|
+
createIfMissing: "// ModWright-scaffolded spell file.\n"
|
|
49
|
+
anchor: append
|
|
50
|
+
body: |
|
|
51
|
+
// ${project.today} - ModWright scaffold: ${input.entryName}, using parent ${input.parent}.
|
|
52
|
+
new entry "${input.entryName}"
|
|
53
|
+
type "SpellData"
|
|
54
|
+
data "SpellType" "${input.spellType}"
|
|
55
|
+
using "${input.parent}"
|
|
56
|
+
data "Icon" "${input.entryName}_Icon"
|
|
57
|
+
data "Level" "${input.level}"
|
|
58
|
+
data "UseCosts" "ActionPoint:1;SpellSlotsGroup:1:1:${input.level}"
|
|
59
|
+
data "DisplayName" "${ids.display}"
|
|
60
|
+
data "Description" "${ids.description}"
|
|
61
|
+
- op: insert-loca-row
|
|
62
|
+
path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
|
|
63
|
+
handle: "${ids.display}"
|
|
64
|
+
text: "${input.displayName}"
|
|
65
|
+
- op: insert-loca-row
|
|
66
|
+
path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
|
|
67
|
+
handle: "${ids.description}"
|
|
68
|
+
text: "${input.description}"
|
|
69
|
+
templates: []
|
|
70
|
+
satisfies:
|
|
71
|
+
- bg3.history.spellanimation-present
|
|
72
|
+
- bg3.history.reference-integrity
|
|
73
|
+
- bg3.history.handle-form-per-field
|
|
74
|
+
- bg3.history.handle-defined-in-loca
|
|
75
|
+
- bg3.history.islinkedspellcontainer-links
|
|
76
|
+
- bg3.history.spellid-enumeration-drift
|
|
77
|
+
- bg3.history.loca-no-xml-comments
|
|
78
|
+
manual:
|
|
79
|
+
- title: Icon and progression
|
|
80
|
+
steps:
|
|
81
|
+
- "Draw the ${input.entryName}_Icon art and register it in the spell atlas."
|
|
82
|
+
- "Add ${input.entryName} to a SpellList or Progression's AddSpells/SelectSpells if the parent does not already grant it."
|
|
83
|
+
expected: "The spell shows a real icon and is grantable in character creation / level-up."
|
|
84
|
+
claim:
|
|
85
|
+
idSuffix: applies
|
|
86
|
+
claim: "Casting ${input.entryName} applies the effect inherited from ${input.parent} for a target."
|
|
87
|
+
testRows:
|
|
88
|
+
- gate: S-1
|
|
89
|
+
title: "Stat entry loads with expected fields"
|
|
90
|
+
expected: "bg3.stat.exists finds ${input.entryName}; bg3.stat.fields confirms SpellType/UseCosts/DisplayName/Description."
|
|
91
|
+
manual: false
|
|
92
|
+
probes:
|
|
93
|
+
- kind: bg3.stat.exists
|
|
94
|
+
params: { name: "${input.entryName}" }
|
|
95
|
+
- kind: bg3.stat.fields
|
|
96
|
+
params: { name: "${input.entryName}", fields: [SpellType, UseCosts, DisplayName, Description] }
|
|
97
|
+
- gate: S-2
|
|
98
|
+
title: "Icon and tooltip render"
|
|
99
|
+
expected: "The spell's card shows the drawn icon and correct tooltip text in-game."
|
|
100
|
+
manual: true
|
|
101
|
+
probeKinds: []
|
|
102
|
+
evidence: ["ModWright research"]
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# new-status (BG3). Same
|
|
2
|
+
# shape as new-spell/new-passive, targeting Status_<GROUP>.txt.
|
|
3
|
+
#
|
|
4
|
+
# Observed in game (2026-09-11): a child
|
|
5
|
+
# status inherits its parent's StackId through `using`, so the scaffolded
|
|
6
|
+
# status (parent BLESS) was replaced the moment BLESS was applied; the entry
|
|
7
|
+
# now restates StackId as its own name. The same launch showed the old
|
|
8
|
+
# "DisableCombatLog" spelling ignored by the engine (the status still hit the
|
|
9
|
+
# combat log; working entries spell it DisableCombatlog), so the
|
|
10
|
+
# flags are an input with the engine's spelling, empty (visible) by default.
|
|
11
|
+
id: baldursgate3.new-status
|
|
12
|
+
game: baldursgate3
|
|
13
|
+
title: New BG3 status (StatusData entry)
|
|
14
|
+
summary: Append a StatusData entry to Status_<GROUP>.txt with a vanilla `using` parent, plus DisplayName/Description loca rows.
|
|
15
|
+
modTypes: [dialogue]
|
|
16
|
+
needs: { index: true }
|
|
17
|
+
inputs:
|
|
18
|
+
- type: string
|
|
19
|
+
name: entryName
|
|
20
|
+
prompt: "Full stats entry name, e.g. MYMOD_SHOCKED."
|
|
21
|
+
pattern: "^[A-Za-z][A-Za-z0-9_]*$"
|
|
22
|
+
- type: enum
|
|
23
|
+
name: group
|
|
24
|
+
prompt: "Status group (also names the Status_<GROUP>.txt file)."
|
|
25
|
+
values: [BOOST, INCAPACITATED]
|
|
26
|
+
- type: index-ref
|
|
27
|
+
name: parent
|
|
28
|
+
prompt: "Vanilla (or project) StatusData entry to `using`."
|
|
29
|
+
lookup: { kind: stat, params: { name: "${input.parent}" } }
|
|
30
|
+
requires:
|
|
31
|
+
- path: type
|
|
32
|
+
matches: "^StatusData$"
|
|
33
|
+
reason: "the parent must be a StatusData entry, or `using` inherits fields from the wrong stat family."
|
|
34
|
+
- type: string
|
|
35
|
+
name: displayName
|
|
36
|
+
prompt: "Player-facing status name."
|
|
37
|
+
- type: string
|
|
38
|
+
name: description
|
|
39
|
+
prompt: "Tooltip description text."
|
|
40
|
+
- type: string
|
|
41
|
+
name: turns
|
|
42
|
+
prompt: "Default duration in turns (informational; wired via the caller's own functors)."
|
|
43
|
+
default: "1"
|
|
44
|
+
- type: string
|
|
45
|
+
name: statusPropertyFlags
|
|
46
|
+
prompt: "StatusPropertyFlags, ';'-separated (engine spelling: DisableOverhead, DisableCombatlog, DisablePortraitIndicator, IgnoreResting). Empty keeps the status visible."
|
|
47
|
+
pattern: "^[A-Za-z;]*$"
|
|
48
|
+
default: ""
|
|
49
|
+
ids:
|
|
50
|
+
- name: display
|
|
51
|
+
slot: "display:${input.entryName}"
|
|
52
|
+
form: bg3-handle
|
|
53
|
+
- name: description
|
|
54
|
+
slot: "description:${input.entryName}"
|
|
55
|
+
form: bg3-handle
|
|
56
|
+
emits:
|
|
57
|
+
- op: insert-block
|
|
58
|
+
path: "Public/${project.identity.folder}/Stats/Generated/Data/Status_${input.group}.txt"
|
|
59
|
+
createIfMissing: "// ModWright-scaffolded status file.\n"
|
|
60
|
+
anchor: append
|
|
61
|
+
body: |
|
|
62
|
+
// ${project.today} - ModWright scaffold: ${input.entryName}, using parent ${input.parent}.
|
|
63
|
+
new entry "${input.entryName}"
|
|
64
|
+
type "StatusData"
|
|
65
|
+
using "${input.parent}"
|
|
66
|
+
data "Icon" "${input.entryName}_Icon"
|
|
67
|
+
data "DisplayName" "${ids.display}"
|
|
68
|
+
data "Description" "${ids.description}"
|
|
69
|
+
data "StackId" "${input.entryName}"
|
|
70
|
+
data "StatusPropertyFlags" "${input.statusPropertyFlags}"
|
|
71
|
+
- op: insert-loca-row
|
|
72
|
+
path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
|
|
73
|
+
handle: "${ids.display}"
|
|
74
|
+
text: "${input.displayName}"
|
|
75
|
+
- op: insert-loca-row
|
|
76
|
+
path: "Mods/${project.identity.folder}/Localization/English/${project.identity.folder}.xml"
|
|
77
|
+
handle: "${ids.description}"
|
|
78
|
+
text: "${input.description}"
|
|
79
|
+
templates: []
|
|
80
|
+
satisfies:
|
|
81
|
+
- bg3.history.spellanimation-present
|
|
82
|
+
- bg3.history.boostcontext-initial-event
|
|
83
|
+
- bg3.history.context-qualifier-validity
|
|
84
|
+
- bg3.history.reference-integrity
|
|
85
|
+
- bg3.history.handle-form-per-field
|
|
86
|
+
- bg3.history.handle-defined-in-loca
|
|
87
|
+
- bg3.history.islinkedspellcontainer-links
|
|
88
|
+
- bg3.history.spellid-enumeration-drift
|
|
89
|
+
- bg3.history.loca-no-xml-comments
|
|
90
|
+
manual:
|
|
91
|
+
- title: Icon and application
|
|
92
|
+
steps:
|
|
93
|
+
- "Draw the ${input.entryName}_Icon art and register it in the spell atlas."
|
|
94
|
+
- "Wire ApplyStatus(${input.entryName}, ...) into whichever spell/passive applies it, with a real duration for ${input.turns} turns."
|
|
95
|
+
expected: "The status applies and its icon/tooltip render correctly in-game."
|
|
96
|
+
claim:
|
|
97
|
+
idSuffix: applies
|
|
98
|
+
claim: "ApplyStatus(${input.entryName}, ...) applies the effect inherited from ${input.parent}."
|
|
99
|
+
testRows:
|
|
100
|
+
- gate: S-1
|
|
101
|
+
title: "Stat entry loads with expected fields"
|
|
102
|
+
expected: "bg3.stat.exists finds ${input.entryName}; bg3.stat.fields confirms DisplayName/Description."
|
|
103
|
+
manual: false
|
|
104
|
+
probes:
|
|
105
|
+
- kind: bg3.stat.exists
|
|
106
|
+
params: { name: "${input.entryName}" }
|
|
107
|
+
- kind: bg3.stat.fields
|
|
108
|
+
params: { name: "${input.entryName}", fields: [DisplayName, Description] }
|
|
109
|
+
- gate: S-2
|
|
110
|
+
title: "Status apply confirmed in-game"
|
|
111
|
+
# bg3.entity.status is attested by the registry, but it needs a live
|
|
112
|
+
# entity's own guid to check against — a fact only a human picking a
|
|
113
|
+
# target in a real session has, never something this scaffold's own
|
|
114
|
+
# inputs supply — so this stays a manual row (a person runs
|
|
115
|
+
# bg3.entity.status by hand via bridge arm/poll after ApplyStatus).
|
|
116
|
+
expected: "A human confirms bg3.entity.status (run by hand, no scaffold-known guid) reports the status active on a target after ApplyStatus."
|
|
117
|
+
manual: true
|
|
118
|
+
probeKinds: [bg3.entity.status]
|
|
119
|
+
evidence: ["ModWright research"]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# subclass-kit (Baldur's Gate 3) — the authoring sequence for a subclass kit
|
|
2
|
+
# (a monk subclass with its armor and a polearm): the project, a passive and a spell, two items, and the
|
|
3
|
+
# injection that puts the passive and spell on the target list. The
|
|
4
|
+
# injection step carries the entry names the two earlier steps were given.
|
|
5
|
+
id: baldursgate3.subclass-kit
|
|
6
|
+
game: baldursgate3
|
|
7
|
+
title: Subclass kit (passive, spell, armor, weapon, injection)
|
|
8
|
+
summary: Project, a passive and a spell with loca rows, an armor and a weapon with RootTemplates, and the class injection that grants the passive and spell.
|
|
9
|
+
modType: subclass
|
|
10
|
+
inputs:
|
|
11
|
+
- name: modName
|
|
12
|
+
prompt: "Mod name, used for the project and its Mods/<name> and Public/<name> folders, e.g. MyMonkMod."
|
|
13
|
+
steps:
|
|
14
|
+
- id: project
|
|
15
|
+
scaffold: baldursgate3.new-project
|
|
16
|
+
title: The project file and source trees
|
|
17
|
+
skipIf: project-exists
|
|
18
|
+
inputs:
|
|
19
|
+
name: "${sequence.modName}"
|
|
20
|
+
- id: passive
|
|
21
|
+
scaffold: baldursgate3.new-passive
|
|
22
|
+
title: The subclass's signature passive
|
|
23
|
+
- id: spell
|
|
24
|
+
scaffold: baldursgate3.new-spell
|
|
25
|
+
title: The subclass's signature spell
|
|
26
|
+
- id: armor
|
|
27
|
+
scaffold: baldursgate3.new-item
|
|
28
|
+
title: The armor item
|
|
29
|
+
inputs:
|
|
30
|
+
entryKind: Armor
|
|
31
|
+
assets:
|
|
32
|
+
- name: look
|
|
33
|
+
prompt: "The armor's look: an existing VisualBank Resource ID to reuse (lookup kind guid on the vanilla index for a vanilla one, or the project's own), and the icon atlas entry. Give the VisualBank id here."
|
|
34
|
+
inputs: [visualBankId]
|
|
35
|
+
- id: weapon
|
|
36
|
+
scaffold: baldursgate3.new-item
|
|
37
|
+
title: The weapon item (a naginata is a reskinned polearm)
|
|
38
|
+
inputs:
|
|
39
|
+
entryKind: Weapon
|
|
40
|
+
assets:
|
|
41
|
+
- name: look
|
|
42
|
+
prompt: "The weapon's look: an existing VisualBank Resource ID to reuse (a vanilla polearm's, from lookup kind guid), and the icon atlas entry. Give the VisualBank id here."
|
|
43
|
+
inputs: [visualBankId]
|
|
44
|
+
- id: injection
|
|
45
|
+
scaffold: baldursgate3.new-class-injection
|
|
46
|
+
title: The injection that grants the passive and spell to the target list
|
|
47
|
+
inputs:
|
|
48
|
+
injectedSpells: "${steps.spell.inputs.entryName}"
|
|
49
|
+
injectedPassives: "${steps.passive.inputs.entryName}"
|
|
50
|
+
evidence: []
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# edit-tweak (Cyberpunk 2077) — the target-side registration a quickhack
|
|
2
|
+
# needs on an existing record. Appends or sets
|
|
3
|
+
# flats on an EXISTING TweakDB record, in place: `RecordName: { flats }` with
|
|
4
|
+
# no `$base`/`$type` is TweakXL's third record form — it MODIFIES the named
|
|
5
|
+
# record rather than creating one. `new-tweak` cannot write it (its recordName
|
|
6
|
+
# collision check refuses a record that already exists — the exact opposite of
|
|
7
|
+
# what an edit needs), so this is a separate scaffold rather than a third
|
|
8
|
+
# new-tweak mode: overloading one recordName input with both "must not exist"
|
|
9
|
+
# (create) and "must exist" (edit) is what the two scaffolds keep apart.
|
|
10
|
+
#
|
|
11
|
+
# recordName is an `index-ref`, so the engine verifies the target actually
|
|
12
|
+
# resolves in the vanilla index before an edit is written to it (a typo would
|
|
13
|
+
# otherwise make TweakXL create a stray record). That also scopes this scaffold
|
|
14
|
+
# to VANILLA records — a project record just authored is not in the vanilla
|
|
15
|
+
# index; edit those by hand in the same file.
|
|
16
|
+
#
|
|
17
|
+
# The quickhack chain uses it to register the hack on NPC hack lists: the game
|
|
18
|
+
# offers a hack on an NPC only when that NPC's `objectActions` names it (matched
|
|
19
|
+
# by actionName), and human/mechanical NPCs inherit their list from
|
|
20
|
+
# Character.Interactable_NPC_Base / Character.Mechanical_NPC_Base.
|
|
21
|
+
id: cyberpunk2077.edit-tweak
|
|
22
|
+
game: cyberpunk2077
|
|
23
|
+
title: Edit an existing Cyberpunk 2077 TweakDB record
|
|
24
|
+
summary: Append or set flats on an existing vanilla TweakDB record, in place — the base-less/type-less TweakXL modify form new-tweak cannot write.
|
|
25
|
+
modTypes: [gameplay-tweak, quickhack, weapon, item, loot]
|
|
26
|
+
needs: { index: true }
|
|
27
|
+
inputs:
|
|
28
|
+
- type: path
|
|
29
|
+
name: file
|
|
30
|
+
prompt: "Destination .yaml under a project source of kind \"tweaks\" (created if it does not yet exist)."
|
|
31
|
+
mustExist: false
|
|
32
|
+
- type: index-ref
|
|
33
|
+
name: recordName
|
|
34
|
+
prompt: "The EXISTING vanilla record to edit, e.g. Character.Interactable_NPC_Base — verified to resolve in the vanilla index before the edit is written."
|
|
35
|
+
lookup: { kind: record, params: { name: "${input.recordName}" } }
|
|
36
|
+
requires: []
|
|
37
|
+
- type: string
|
|
38
|
+
name: flats
|
|
39
|
+
prompt: "The flats to append or set on the record, as YAML (e.g. \"objectActions:\\n - !append QuickHack.MyHack\"). Indentation is normalized to nest under the record."
|
|
40
|
+
default: ""
|
|
41
|
+
reindent: 2
|
|
42
|
+
ids: []
|
|
43
|
+
emits:
|
|
44
|
+
# No $base/$type line: a record block with only flats modifies the existing
|
|
45
|
+
# record. `${input.flats}` is normalized to 2-space indent (reindent) so it
|
|
46
|
+
# nests under the record name.
|
|
47
|
+
- op: insert-block
|
|
48
|
+
path: "${input.file}"
|
|
49
|
+
createIfMissing: ""
|
|
50
|
+
anchor: append
|
|
51
|
+
body: |
|
|
52
|
+
${input.recordName}:
|
|
53
|
+
${input.flats}
|
|
54
|
+
templates: []
|
|
55
|
+
satisfies:
|
|
56
|
+
- cp2077.tweaks.yaml-lint
|
|
57
|
+
- cp2077.tweaks.append-on-list-flat
|
|
58
|
+
- cp2077.tweaks.record-name-exists
|
|
59
|
+
- cp2077.tweaks.dotted-path-same-file
|
|
60
|
+
- cp2077.tweaks.instances-resolve
|
|
61
|
+
manual:
|
|
62
|
+
- title: Confirm the edit landed
|
|
63
|
+
steps:
|
|
64
|
+
- "Load a save with the mod active and confirm the TweakXL log shows no error for ${input.file}."
|
|
65
|
+
- "Inspect ${input.recordName} and confirm the appended flats are present alongside its vanilla values (an edit adds to, it does not replace, unless a flat is set outright)."
|
|
66
|
+
expected: "TweakXL-<timestamp>.log carries no error for this file, and ${input.recordName} reads with both its vanilla flats and the appended ones."
|
|
67
|
+
claim:
|
|
68
|
+
idSuffix: edits
|
|
69
|
+
claim: "${input.recordName} carries the flats this run appended, on top of its vanilla definition."
|
|
70
|
+
evidence: ["ModWright research"]
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# mesh-export-preset (Cyberpunk 2077). Writes a parameterised Blender export
|
|
2
|
+
# script encoding the confirmed pipeline facts
|
|
3
|
+
# (`knowledge/cyberpunk2077/mesh.blender.yaml`: the 65,535-vertex-per-submesh
|
|
4
|
+
# cap, exactly one "UVMap" UV layer, triangulation, baked tangents) and
|
|
5
|
+
# appends the `blender-export` + `wolvenkit-import` step pair to
|
|
6
|
+
# `build.steps` as `optional: true`, the shape a working project's own
|
|
7
|
+
# export-then-import build takes.
|
|
8
|
+
#
|
|
9
|
+
# The generated script is a parameterised **rewrite** of the confirmed facts,
|
|
10
|
+
# not a copy of any particular project's export script: the knowledge base
|
|
11
|
+
# attests that behaviour (vertex cap, UV normalisation, triangulation,
|
|
12
|
+
# tangent export, the 00/01/02/03 submesh join order) rather than quoting
|
|
13
|
+
# literal text. This scaffold never invokes Blender or WolvenKit itself; it
|
|
14
|
+
# only writes the script and the two `optional: true` build steps a real run
|
|
15
|
+
# would exercise.
|
|
16
|
+
id: cyberpunk2077.mesh-export-preset
|
|
17
|
+
game: cyberpunk2077
|
|
18
|
+
title: New Cyberpunk 2077 mesh export preset
|
|
19
|
+
summary: Write a parameterised Blender export script (vertex cap, UV, triangulation, tangents) and append the blender-export + wolvenkit-import build steps as optional.
|
|
20
|
+
modTypes: [mesh, garment, weapon, vehicle]
|
|
21
|
+
needs: {}
|
|
22
|
+
inputs:
|
|
23
|
+
- type: path
|
|
24
|
+
name: blendFile
|
|
25
|
+
prompt: "The .blend this preset exports from."
|
|
26
|
+
mustExist: false
|
|
27
|
+
- type: path
|
|
28
|
+
name: exportScriptFile
|
|
29
|
+
prompt: "Destination for the generated export script."
|
|
30
|
+
mustExist: false
|
|
31
|
+
- type: path
|
|
32
|
+
name: baseMeshPath
|
|
33
|
+
prompt: "Existing staged .mesh WolvenKit imports the exported glb over (donor chunkMaterials/skinning)."
|
|
34
|
+
mustExist: false
|
|
35
|
+
- type: path
|
|
36
|
+
name: outputMeshDir
|
|
37
|
+
prompt: "Directory the imported .mesh should land in."
|
|
38
|
+
mustExist: false
|
|
39
|
+
- type: string
|
|
40
|
+
name: glbOutputPath
|
|
41
|
+
prompt: "Where the exported .glb should land — may use the build system's own ${stage} placeholder, e.g. \"${stage}/mymod.glb\"."
|
|
42
|
+
- type: string
|
|
43
|
+
name: uvLayerName
|
|
44
|
+
prompt: "Required single UV layer name (cp2077.mesh.glb-uv-layers-required)."
|
|
45
|
+
default: "UVMap"
|
|
46
|
+
- type: string
|
|
47
|
+
name: presetId
|
|
48
|
+
prompt: "Short id for this preset, used to name the two build steps, e.g. mymod."
|
|
49
|
+
pattern: "^[a-z][a-z0-9_-]*$"
|
|
50
|
+
ids: []
|
|
51
|
+
emits:
|
|
52
|
+
- op: write-text
|
|
53
|
+
path: "${input.exportScriptFile}"
|
|
54
|
+
body: |
|
|
55
|
+
#!/usr/bin/env python3
|
|
56
|
+
# ${project.today} — ModWright scaffold: parameterised Blender export
|
|
57
|
+
# preset "${input.presetId}", generated by cyberpunk2077.mesh-export-preset.
|
|
58
|
+
# Encodes the confirmed Cyberpunk 2077 mesh-export pipeline facts
|
|
59
|
+
# (knowledge/cyberpunk2077/mesh.blender.yaml), written as a parameterised
|
|
60
|
+
# rewrite of those facts. Run via:
|
|
61
|
+
# blender --background "${input.blendFile}" --python "${input.exportScriptFile}"
|
|
62
|
+
import os
|
|
63
|
+
import bpy
|
|
64
|
+
|
|
65
|
+
VERTEX_CAP_PER_SUBMESH = 65535 # cp2077.mesh.vertex-cap-65535
|
|
66
|
+
REQUIRED_UV_LAYER = "${input.uvLayerName}" # cp2077.mesh.glb-uv-layers-required
|
|
67
|
+
# The build step's own "out"/"glb" fields (modwright.json) are the
|
|
68
|
+
# authoritative destination — they may use ModWright's own ${stage}
|
|
69
|
+
# placeholder, which only that build system resolves, never this
|
|
70
|
+
# script. This script writes next to the source .blend and lets the
|
|
71
|
+
# wolvenkit-import step (or you) move/copy from there, the way a
|
|
72
|
+
# plain export invocation takes no output argument
|
|
73
|
+
# (knowledge/cyberpunk2077/mesh.blender.yaml).
|
|
74
|
+
GLB_OUTPUT_PATH = os.path.splitext(bpy.data.filepath)[0] + ".glb"
|
|
75
|
+
|
|
76
|
+
def normalize_uv_layers(mesh_obj):
|
|
77
|
+
# Exactly one UV layer named REQUIRED_UV_LAYER; extra layers removed,
|
|
78
|
+
# missing ones smart-projected (cp2077.mesh.glb-uv-layers-required).
|
|
79
|
+
uv_layers = mesh_obj.data.uv_layers
|
|
80
|
+
if REQUIRED_UV_LAYER not in uv_layers:
|
|
81
|
+
bpy.ops.object.mode_set(mode="EDIT")
|
|
82
|
+
bpy.ops.uv.smart_project(angle_limit=1.15, island_margin=0.02)
|
|
83
|
+
bpy.ops.object.mode_set(mode="OBJECT")
|
|
84
|
+
uv_layers.active.name = REQUIRED_UV_LAYER
|
|
85
|
+
for layer in list(uv_layers):
|
|
86
|
+
if layer.name != REQUIRED_UV_LAYER:
|
|
87
|
+
uv_layers.remove(layer)
|
|
88
|
+
|
|
89
|
+
def triangulate_and_check_cap(mesh_obj):
|
|
90
|
+
# cp2077.mesh.glb-triangulation-required
|
|
91
|
+
bpy.ops.object.mode_set(mode="EDIT")
|
|
92
|
+
bpy.ops.mesh.quads_convert_to_tris(quad_method="BEAUTY", ngon_method="BEAUTY")
|
|
93
|
+
bpy.ops.object.mode_set(mode="OBJECT")
|
|
94
|
+
if len(mesh_obj.data.vertices) > VERTEX_CAP_PER_SUBMESH:
|
|
95
|
+
raise RuntimeError(
|
|
96
|
+
f"{mesh_obj.name}: {len(mesh_obj.data.vertices)} vertices exceeds the "
|
|
97
|
+
f"{VERTEX_CAP_PER_SUBMESH}-per-submesh engine cap (cp2077.mesh.vertex-cap-65535)."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def export():
|
|
101
|
+
for obj in bpy.context.scene.objects:
|
|
102
|
+
if obj.type != "MESH":
|
|
103
|
+
continue
|
|
104
|
+
normalize_uv_layers(obj)
|
|
105
|
+
triangulate_and_check_cap(obj)
|
|
106
|
+
bpy.ops.export_scene.gltf(
|
|
107
|
+
filepath=GLB_OUTPUT_PATH,
|
|
108
|
+
export_tangents=True, # cp2077.mesh.glb-tangent-vectors-required
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
if __name__ == "__main__":
|
|
112
|
+
export()
|
|
113
|
+
# Against a fresh new-project output (no `build` block yet at all), a
|
|
114
|
+
# patch-project without `build.outDir` would leave modwright.json failing
|
|
115
|
+
# to reload ("build.outDir: Required"), the same gap new-sector-node's
|
|
116
|
+
# patch-project closes. `add.outDir` only fills a genuinely missing
|
|
117
|
+
# `build.outDir`, so a project that already set one (e.g. from an earlier
|
|
118
|
+
# scaffold's own patch-project) keeps its own value (the engine's merge).
|
|
119
|
+
# Both steps below share one id on purpose: a build step id names a
|
|
120
|
+
# *chain* for `build --only <id>` (src/core/project/types.ts, BuildStepBase),
|
|
121
|
+
# so a blender-export and wolvenkit-import pair given a single id run
|
|
122
|
+
# together under `--only <id>`. That shared id is the convention, not a
|
|
123
|
+
# bug.
|
|
124
|
+
- op: patch-project
|
|
125
|
+
add:
|
|
126
|
+
outDir: "archive-staging"
|
|
127
|
+
steps:
|
|
128
|
+
- step: blender-export
|
|
129
|
+
id: "mesh-export-${input.presetId}"
|
|
130
|
+
optional: true
|
|
131
|
+
blend: "${input.blendFile}"
|
|
132
|
+
script: "${input.exportScriptFile}"
|
|
133
|
+
out: "${input.glbOutputPath}"
|
|
134
|
+
- step: wolvenkit-import
|
|
135
|
+
id: "mesh-export-${input.presetId}"
|
|
136
|
+
optional: true
|
|
137
|
+
glb: "${input.glbOutputPath}"
|
|
138
|
+
base: "${input.baseMeshPath}"
|
|
139
|
+
outDir: "${input.outputMeshDir}"
|
|
140
|
+
templates: []
|
|
141
|
+
# Applied against a fresh cyberpunk2077.new-project output,
|
|
142
|
+
# cp2077.history.mesh-preexport always skipped "no file matched": this
|
|
143
|
+
# scaffold never invokes Blender or WolvenKit itself and only writes the
|
|
144
|
+
# script and the two optional: true build steps, so it never writes a
|
|
145
|
+
# .gltf/.glb for that rule to check. The rule is therefore in the manual
|
|
146
|
+
# checklist below, which names the real file (the exported .glb at
|
|
147
|
+
# ${input.glbOutputPath}) and the checks the rule performs in prose.
|
|
148
|
+
# cp2077.history.archive-name-sort-order/deploy-set-completeness stay: both
|
|
149
|
+
# are project-scoped (appliesTo: project) and genuinely run every time.
|
|
150
|
+
satisfies:
|
|
151
|
+
- cp2077.history.archive-name-sort-order
|
|
152
|
+
- cp2077.history.deploy-set-completeness
|
|
153
|
+
manual:
|
|
154
|
+
- title: The kitbash and export itself
|
|
155
|
+
steps:
|
|
156
|
+
- "Author/kitbash the mesh in ${input.blendFile}, joined by material in the fixed submesh order this project's own donor mesh established (cp2077.mesh.join-by-material-submesh-order)."
|
|
157
|
+
- "Run the generated script (blender --background \"${input.blendFile}\" --python \"${input.exportScriptFile}\") and confirm no vertex-cap or UV error."
|
|
158
|
+
- "Build with this step pair enabled, then confirm the imported .mesh's chunkMaterials line up with the donor (${input.baseMeshPath})."
|
|
159
|
+
- "Once ${input.glbOutputPath} exists on disk, run validate against it directly — cp2077.history.mesh-preexport (moved out of this scaffold's own satisfies[]: it checks a .gltf/.glb this scaffold itself never produces) confirms the vertex cap, UV layer, triangulation and tangent-vector facts encoded in the generated script actually held for the real export."
|
|
160
|
+
expected: "The mesh imports cleanly with correct chunkMaterials, every submesh is under the 65,535-vertex cap, and cp2077.history.mesh-preexport reports no finding against the real ${input.glbOutputPath}."
|
|
161
|
+
claim:
|
|
162
|
+
idSuffix: mesh-exports-clean
|
|
163
|
+
claim: "${input.blendFile} exports through ${input.exportScriptFile} and imports over ${input.baseMeshPath} with no vertex-cap or UV-layer error."
|
|
164
|
+
testRows:
|
|
165
|
+
- gate: M-1
|
|
166
|
+
title: "Export and import run without error"
|
|
167
|
+
expected: "blender-export and wolvenkit-import both report success for the ${input.presetId} preset, with no vertex-cap/UV/triangulation error."
|
|
168
|
+
manual: true
|
|
169
|
+
probeKinds: []
|
|
170
|
+
evidence: ["ModWright research"]
|