
如果你看过《UNDERTALE》的同人二创区大概率会对“假如其他sans来到原版时间线”这类标题不陌生。它几乎是把同人圈最有吸引力的两个命题直接粘在一起一个是“如果外来者强行进入主线故事会如何失控”另一个是“这个能够记住重置、看穿因果的骷髅角色面对另一个自己时到底会做什么”。很多人点开视频之后的第一反应是“很震撼但没有完全看懂”。为什么因为这类创作表面上讲的是角色相遇实际上讲的是世界观规则之间的冲突。而世界观规则这件事恰恰是软件工程师每天都要处理的问题。如果你把“原版时间线”理解成发布分支把“其他sans”理解成来自另一个分叉仓库的提交把“穿越”理解成一次跨分支合并那么整段剧情的逻辑会变得异常清晰。这篇博客不做剧情考据也不讨论某个具体AU的角色强度排行。我会用版本管理这套技术模型把“其他sans来到原版时间线”这个经典命题拆开再把它背后的同人动画制作工程讲清楚。读完你会得到两样东西一套用来理解同人叙事的新工具以及一套真正能落到创作落地阶段的素材管理与协作方法。1. 这篇文章真正要解决的三个问题第一为什么“其他sans来到原版时间线”这类故事天然好看而且容易造成剧情失控因为它本质上是一次违反分支保护规则的跨分支合并。外来sans不是原版时间线的本地提交他自带另一套记忆、能力体系和目标。合并发生时原版角色对他的了解程度、信任程度、战斗力评估全部失效冲突不是偶然而是结构性必然。第二为什么很多观众看完之后会“懵”因为这类创作默认观众已经知道《UNDERTALE》官方的重置机制、sans在屠杀线路中的行为以及AU文化的核心设定。如果你只看了零散片段很容易把“sans”当成同一个角色进而觉得剧情莫名其妙。本文会给出一个更精确的框架同一角色名在不同时间线上是不同的快照对象。第三同人动画这种内容形态到底需要什么样的工程能力很多人以为它是“画几张图、配个音乐”的事情实际上从分镜到动画到剪辑到多人协作每一步都可能毁在素材管理上。本文会给出目录规范、版本管理方案和协作分工建议这部分对所有做视频创作的人都有参考价值。本文的目标读者是三类人正在追这类AU视频但总觉得没看懂的技术人自己也在做同人动画、需要工程化方法的内容创作者以及想用软件工程思维重新理解叙事模型的开发者。如果你是纯路人也能通过“分支、快照、合并冲突、回滚”这套概念快速进入同人世界观的讨论语境。2. 基础概念把《UNDERTALE》同人宇宙当成一棵分支树2.1 原版时间线 main 分支在官方游戏《UNDERTALE》里时间线并不是一个可以随便改写的系统但它确实存在“重置”的设定拥有决心的人类灵魂在死亡或结局达成后可以重置世界让所有人都回到起点。这件事用版本管理类比就是重置到某个历史提交。“原版时间线”并不是官方明确给出的一个分支名它更多是同人圈的公共认知玩家第一次进入地下世界、完成普通结局或和平结局时所经历的那条线。把它理解成main分支没有问题。它的特征是稳定、被多数人认可、承担着“标准叙事”的角色。官方游戏流程就是这一条主干上的完整提交历史。2.2 AU 世界 fork 出的独立仓库同人AUAlternate Universe本质上是从原版 fork 出去的独立世界。创作者是仓库维护者他们复制了初始设定然后添加自己的修改换掉某个角色的立场、改写某个关键事件、调整世界规则最终得到一条和原版完全不同的提交历史。你可以把每个AU理解为有自己的main分支。有自己的 commit 历史和官方主仓共享前半段祖先提交。有自己的角色状态快照因此同一个名字sans在不同仓库里的实现完全不一样。“其他sans来到原版时间线”就是一次跨仓库操作把另一个仓库中的某个提交应用到原版仓库的主干上。2.3 角色版本 commit 上的快照理解这个问题的关键是sans 不是一个全局单例对象。官方原版里的 sans和UnderFell里的sans、Error!Sans、Ink!Sans虽然共享同一个基础形象资源但内存中的状态、技能列表、记忆栈、行为逻辑完全不同。用代码表达就是// 原版时间线中的 sans 状态快照 { character_id: sans, timeline: original, memory_ids: [judgment_day, papyrus_bound, promise_kept], intent: observe_and_judge, abilities: [shortcut, gaster_blaster, bones] }// 另一个时间线中的 sans 状态快照 { character_id: sans, timeline: alternate-001, memory_ids: [world_destroyed, no_papyrus, war_survivor], intent: destroy_or_protect, abilities: [error_corruption, summon_blue, timeline_travel] }两个JSON字段里的timeline、memory_ids、intent完全不同。当第二个对象被强行放进原版时间线时它携带的外部依赖记忆、目标、能力在原版上下文中找不到对应接口系统自然会报出“合并冲突”。2.4 核心术语对照表同人叙事概念软件工程概念说明原版时间线main/ 主干分支默认叙事基线AU 世界fork 仓库 / 特性分支从主干分叉出的独立世界sans 的另一个版本不同仓库中的同名对象快照名称相同状态不同重置世界git reset --hard恢复历史提交清除后续改动角色穿越到原版cherry-pick / 跨分支合并将一个提交应用到另一分支剧情冲突合并冲突merge conflict两边的修改互不兼容观众记忆混乱上下文切换失败浏览器/命令行状态没有同步这张表是后面所有分析的基础。记住一点在原版时间线里其他sans是一段不可直接运行的代码他需要重新绑定上下文。3. “其他sans来到原版时间线”是一次跨分支合并事故3.1 场景一只读访问一切正常如果外来sans只是短暂观看原版时间线不参与任何事件那么这次操作可以看作“只读快照”。对应在Git里就是git fetch另一个仓库的内容但不执行merge本地主干不会被触碰。这种剧情模型通常很温和。外来sans观察原版角色不改变任何事件节点观众获得的是信息增量而不是剧情破坏。很多同人作品会先安排这个阶段一个陌生sans突然出现但没有立刻改变世界。然而同人视频想要制造看点几乎不会停在只读阶段。因为“只是看看”意味着没有冲突没有冲突就没有戏剧张力。所以第二个场景才是主流。3.2 场景二合并别人的改动当外来sans开始和原版角色说话、战斗、改变某个事件的结局他就从“只读”变成了“写入”。这时候系统要做的事情是把他的行为提交合并到原版时间线的主干上。问题在于原版时间线的历史提交基本是稳定的——角色关系已经建立事件因果已经闭合甚至连“某个时间点谁必须死亡”都写死在剧情脚本里。外来sans的改动一旦合并就会和原有提交产生大量冲突他认识Papyrus但Papyrus不认识他。他知道某个玩家路线会走到什么结局但原版角色不知道。他试图阻止某个事件但那个事件是主线后续逻辑的前置依赖。在Git里这种冲突根本没法自动解决。同人剧情的处理方式通常是两种让外来sans强行改变世界规则或者让原版角色接受新信息后重新决策。但无论哪种都意味着原版时间线已经不再“原版”它变成了一个合并后的新分支。3.3 场景三强制推送与覆盖更极端的情况是外来sans试图覆盖整个原版时间线。用Git术语说就是git push --force。他带来的不是“合并”而是“替换”。这一场景在AU创作里非常常见也是最容易引起观众争议的部分。因为从原版角色的角度看自己的整个世界被人为重置或改写个人意志、记忆、经历全都不再算数。这种冲突本质上是“分支重写权”之争谁有权力覆盖一条已经存在的时间线理解这个模型后你就能看懂为什么这类作品会让观众产生强烈情绪反应。观众对原版sans的情感投入建立在他所在时间线的历史积累之上而强制推送意味着这些历史积累被破坏。剧情里表现出的痛苦、反抗、妥协全是“冲突解决策略”的外在呈现。4. 用软件工程思维拆解这类叙事的三种模型4.1 快照模型只是路过不留下痕迹模型特征外来sans读取原版时间线状态不做任何写入。剧情层面的结果是“他看到了另一个自己然后离开”。这类叙事适合介绍角色设定、建立情感铺垫但它不改变主线。用技术话说这是git diff操作我们查看两个分支之间的差异但本地分支的 HEAD 没有移动。这种模型的软肋是观众看多了会觉得“没有推进”。如果一集视频只停留在“相遇—观察—离开”叙事价值会很快耗尽。它更适合作为大故事的第一集用来交代外来sans的背景。4.2 合并模型外来者真正参与主线模型特征外来sans变成活动对象与主线角色产生交互事件路径发生偏移最终形成一个新的、融合了双方记忆的时间线状态。这是“假如其他sans来到原版时间线”最典型的展开方式。对应到工程上就是一次真实的git merge或git cherry-pick。合并完成后历史不是简单替换而是产生了新的合并提交双边的变更都在新状态里有所体现。从创作者视角看这个模型的可控性最好。你可以保留原版角色的人设基础再叠加外来sans带来的变量。观众既能看到熟悉的世界观又能感受到“出格”的新鲜感。这也是大多数同人长剧集选择的叙事结构。4.3 重置模型把原版时间线推向另一个状态模型特征外来sans拥有覆盖能力最终原版时间线被改写所有角色被推到一条新的命运路径。对应到Git相当于对外来提交执行了git reset --hard HEAD~3历史提交丢失世界回到新起点。这种模型的冲击力最强风险也最大。因为它非常依赖观众对外来sans动机的理解。如果观众没有接受“为什么他要这么做”那么整个覆盖行为就显得强制和生硬。而一旦接受了动机这种模型往往是催泪和震撼的根源。创作者在选择模型时其实是在回答一个问题你要让这条时间线变成谁的提交历史这比确定角色强度更重要因为它定义了整个故事的价值观。5. 从“看懂故事”到“做出故事”同人动画制作工程拆解5.1 这类动画的基本制作环节虽然我不清楚这部《假如其他sans来到原版时间线...?-骷进重澜 新第一集 【空潮虚寞 主】》具体使用了什么工具链但从同类AU动画的常见制作路径来看流程大体包括脚本、分镜、角色原画、动画、背景、配音、音效、剪辑、合成、字幕、压制发布。很多个人创作者会压缩到极简流程使用像素风或者纸片人式的表现方式降低原画工作量使用模板化配音和BGM优先把剧情和节奏做出来。这样做可以保证“一集视频能在合理周期内发出来”而不是陷入无限打磨的质量黑洞。对于刚开始做这类内容的人我的建议是不要一上来就追求剧场级质量。先做一集能完整表达剧情的产物跑通全流程再考虑美术升级和动画表现力。这在工程上叫“先做最小可用版本”。5.2 素材管理与目录规范无论你用哪种工具素材命名混乱都是最大的时间杀手。一部作品往往包含角色立绘、差分表情、背景图、特效素材、配音文件、音乐文件、剪辑工程、字幕文件、版本导出文件。如果不做目录规范第三周你就会发现“最终版_final_真的最终版_v2”这类文件出现。推荐目录结构project_root/ ├── 00_docs/ # 脚本、分镜、设定文档 │ ├── script/ │ ├── storyboard/ │ └── world_setting/ ├── 01_assets/ # 原始素材 │ ├── character/ # 按角色建子目录 │ │ ├── sans_original/ │ │ ├── sans_alt/ │ │ └── papyrus/ │ ├── background/ # 场景背景 │ ├── effect/ # 光效、粒子、特效 │ └── sound/ # 配音、音效、BGM ├── 02_working/ # 中间工程文件 │ ├── animation/ │ ├── compositing/ │ └── edit/ ├── 03_release/ # 发布版本 │ ├── v1_preview/ │ ├── v2_rc/ │ └── v3_final/ └── README.md # 记录每集状态和改动命名规范建议使用集数_场景_角色_动作_版本格式例如ep01_scene03_sans_enter_v01.png ep01_scene03_sans_enter_v01.psd这套规范和代码仓库的命名哲学完全一致让文件本身携带上下文信息而不是靠人类记忆去关联。5.3 善用 Git LFS 管理大文件说到版本管理很多人会问视频项目能用Git吗能用但大文件必须交给Git LFSLarge File Storage。普通仓库会把PSD、配音WAV、视频片段当作大文件导致克隆和提交极其缓慢LFS则会把大文件指针存入仓库真实内容存到远程存储服务。在项目根目录添加.gitattributes# 标记需要由 Git LFS 接管的大文件类型 *.psd filterlfs difflfs mergelfs textfalse *.wav filterlfs difflfs mergelfs textfalse *.mp4 filterlfs difflfs mergelfs textfalse *.mov filterlfs difflfs mergelfs textfalse *.aep filterlfs difflfs mergelfs textfalse初始化LFSgit lfs install git lfs track *.psd git lfs track *.wav git lfs track *.mp4 git add .gitattributes git commit -m chore: add git lfs tracking for big media files需要注意的是Git LFS并不能解决所有协作问题。它只负责版本追踪不负责团队同步的沟通纪律。即使有LFS也应该避免两个人在同一时间编辑同一个Prate文件否则合并冲突仍然会让你崩溃。5.4 多人协作分工建议同人动画进入多人协作阶段后最容易出事的往往不是制作而是“交接”。原画、动画、配音、剪辑各环节都会产生中间版本如果每个人在自己的本地目录里存文件然后用网盘传来传去那么版本错乱只是时间问题。比较稳妥的方式是由一个人维护“发布基线”所有素材以这个基线的版本为准其他人只提交增量改动并附带说明。简单说就是让整个项目有一个唯一的main分支而不是每个人各自维护一个私有主干。这看起来很基础却是大多数个人项目翻车的原因。如果你只是自己做着玩完全可以不搞这套但只要超过两个人协作请务必先定规则再动手。6. 一个最小示例用 Git 模拟一次时间线入侵接下来做一个可以直接运行的实验用Git本身模拟“其他sans来到原版时间线”的过程。这个实验不依赖任何视频素材只需要一台装好Git的电脑十分钟内能看到结果。6.1 准备仓库首先创建一个演示用的Git仓库mkdir sans-timeline-demo cd sans-timeline-demo git init git config user.name sans git config user.email sansundertale-demo.local cat timeline.md EOF # 原版时间线 - 玩家落入地下世界 - 遇到Papyrus - 在雪镇与sans对话 - 走到最终结局 EOF git add timeline.md git commit -m feat: 初始化原版时间线这一条提交就是“原版时间线”的初始状态。6.2 创建“外来sans”分支新建一个分支代表另一条时间线中的sansgit checkout -b sans-alt cat alt_plan.md EOF # 外来sans计划 - 阻止原版结局发生 - 改变Papyrus的命运 - 尝试覆盖时间线 EOF git add alt_plan.md git commit -m feat: 外来sans带着自己的计划进入时间线此时本地有两个分支main代表原版时间线sans-alt代表外来sans携带的改动。6.3 模拟合并冲突现在执行“外来sans来到原版时间线”的合并操作git checkout main git merge sans-alt这次合并会成功因为两条分支修改的是不同文件。但这也说明一个关键问题剧情冲突不取决于文件是否同名而取决于改动是否触及同一条语义依赖。所以下一步我们把两个sans的状态写进同一个文件制造真正的冲突。在main分支里修改角色配置cat character.json EOF { character: sans, timeline: original, ability: shortcut, memory: judgment } EOF git add character.json git commit -m feat: 原版sans状态切回sans-alt分支修改同一个文件git checkout sans-alt cat character.json EOF { character: sans, timeline: alternate, ability: corruption, memory: world_destroyed } EOF git add character.json git commit -m feat: 外来sans状态再次合并git checkout main git merge sans-alt这次Git会报告冲突character.json进入冲突状态。查看冲突文件cat character.json在输出中会看到 HEAD和 sans-alt之间的冲突标记。这就是“外来sans进入原版时间线”的代码级表达两边都不愿意放弃自己的状态。6.4 观察结果现在你需要决定如何解决冲突。选择原版状态、外来状态或者手动融合出一个新状态。这个决策动作本质上就是同人作者在写的“剧情推进”。Git实验到这里你应该已经理解了一个抽象但重要的结论冲突不是异常而是两个上下文合并时的必然产物。同人动画里的战斗、对峙、妥协全都是冲突解决策略的具象化。7. 常见理解误区与排查思路7.1 “sans到底是不是时间线管理者”不是。在官方《UNDERTALE》中sans并没有明确表现出“时间线管理者”的身份。他在屠杀线路里的行为更多是基于观察和判断。能感知重置的另有角色比如Flowey。同人圈里“sans能记住重置”“sans打破第四面墙”的说法属于二创演绎而不是官方准则。观众如果把二创设定当成官方设定就会对剧情产生错误预期。建议在讨论时明确区分这是官方设定、同人常见设定、还是本作专属设定。7.2 “为什么重置之后大家还有记忆”官方设定中重置不是所有人都会失去记忆。拥有强大决心或特殊连接的角色可能保留部分记忆。而同人作品里的“记忆保留”往往是为了服务剧情。用版本管理的语言说重置相当于git reset --hard但某些角色相当于“外挂进程”运行在版本系统之外所以重置对他们只影响文件系统不影响进程内存。这类角色天然适合做穿越剧情的主角因为只有他们还记得“之前发生过什么”。7.3 “为什么外来sans在原版里看起来会ooc”ooc是“Out of Character”的缩写意思是角色行为偏离了大家在原版中形成的认知。这句话隐含一个预设所有sans应该共享同一套性格。但从版本模型看来自不同时间线的sans原本就是不同快照ooc只是快照差异不是错误。真正的问题应该是创作者是否给出了足够合理的背景让观众理解这种差异的来源。如果没给观众就会觉得角色崩坏如果给了那就是一个合理的AU设定。7.4 综合排查表问题现象可能原因排查方式解决方案看不懂剧情缺少官方设定背景先补《UNDERTALE》游戏流程和结局知识阅读官方wiki或看剧情解析觉得sans人设崩坏把不同AU快照当成同一角色确认角色来源时间线按时间线分类理解不要混用设定对“重置记忆”有疑问混淆官方和二创设定查看作品是否声明AU规则以作品内部规则为准战斗中角色能力忽强忽弱不同AU能力体系冲突看创作者是否有能力设定页接受“跨时间线规则会重新结算”的设定这张表可以当成看番时的排错手册。遇到看不懂先问一句这里是哪条时间线这个sans是哪次提交的快照8. 给同人创作者和开发者的共同建议8.1 维护世界观 Changelog同人长剧集最怕“设定前后矛盾”。今天sans还能穿越明天就穿越不了这期Papyrus知道真相下一期他又不知道。观众不会去读你的设定文档但他们会对“记忆一致性”极度敏感。建议为作品维护一个world_changelog.md每次修改世界观规则记录## ep01 - 新增 - 外来sans可以从其他时间线进入原版时间线 - 原版角色初次见面时保留自己的记忆 ## ep02 - 调整 - 外来sans穿越存在冷却时间 - 原因避免能力无限制滥用这不是一个复杂操作但能帮你避免所有长线叙事的致命伤——设定崩塌。8.2 角色也可以做成状态机开发者在设计复杂系统时喜欢把对象建模成状态机空闲、攻击、受击、死亡每个状态定义合法迁移路径。同人创作者同样可以这样管理角色。比如外来sans在原版时间线中的状态可以分为探索状态观察原版角色不展示敌对意图。对峙状态与特定角色发生冲突能力系统启用。妥协状态接受无法改变某些事实调整目标。覆盖状态尝试强制执行自己的时间线方案。给每个状态下定义触发条件和出口条件角色行为就会变得稳定和可预测。这不会限制创作反而会减少“为了冲突而冲突”的剧情混乱。8.3 发布前测试与灰度反馈视频发布前找一个没看过原版设定的路人让他试看前5分钟。如果他能流畅说出“谁、在哪、为什么”说明叙事交代到位了如果他一头雾水说明你的前5分钟是在自嗨。这个概念很接近开发中的“灰度发布”先在最小范围内验证再推向大平台。对创作者来说可以先把样片发给同人圈核心群、信任的审片朋友收集三种反馈设定能不能看懂、情绪有没有到位、节奏会不会拖。而不是直接发布到大平台然后看着差评陷入自我怀疑。8.4 风险意识与二次创作边界同人创作本身存在授权边界问题。不同游戏、动画IP对同人的态度不同《UNDERTALE》社区整体对二创比较开放但这不意味着所有衍生作品都没有边界。创作者应该主动了解原始IP的二次创作规范不用原创角色去冒犯原作角色设定同时避免商业用途带来的版权风险。对开发者来说这也是一种“责任意识”你可以把别人的开源项目fork出来做修改但要保留原作者署名、遵守许可证协议。道理是完全一致的。9. 借助版本思维看懂任何“时间线”故事回到标题里的问题假如其他sans来到原版时间线会发生什么用版本控制回答就是会发生一次必然的跨分支合并冲突无法避免最终状态一定不再是原来的main。这时真正重要的已经不是“谁打赢了”而是“保留和执行了哪些提交”。一段记忆、一条承诺、一次选择在这个模型里统统可以被看作commit信息。原版sans做出的每一个决定都是曾经写入这支时间线的关键提交。理解这层逻辑之后你会发现同类作品真正想讨论的不是战力高低而是世界观不可兼容时角色愿意为哪条时间线保留哪一段历史。这才是“跨分支事故”最有价值的地方。如果你之后再做自己的同人项目可以试着先画一棵逻辑分支图把每个角色的时间线背景写清楚再推动剧情。这样既不会有漏洞百出的设定也能把造成全剧最大情绪冲突的节点精准地安放在跨越分支的那一次合并中。毕竟观众记住的从来不是某段特效而是某条时间线最终被书写的结局。