修:draw-ui / oil-motion 原被当子模块指针收录 ⇒ 改为正常文件入库(两份内容原先对别人是空的)

一、问题(本轮实测)
`draw-ui` 与 `oil-motion` 目录里**各自带一个内嵌 `.git`** ⇒ 上一次提交把它们记成了 **gitlink(子模块指针)**
⇒ 仓库里只存了一个不属于任何远端的 commit id,**别人克隆下来这两份是空的** ✗(`git status` 显示 ` m draw-ui` / ` m oil-motion` = 子模块内容有改动)。

二、处置(可回退)
· 把两处的 `.git` **挪走**(⛔ 不是删除)⇒ `归档/内嵌git-20261008/{draw-ui,oil-motion}.git`;
· `git rm --cached` 掉那两个 gitlink,再 `git add` 两个目录 ⇒ **按正常文件入库**(内容才真的进仓库)。

三、副作用(如实记)
挪走 `.git` 后,这两个技能**不能再原地 `git pull` 取上游更新**(要更新得重新拉一份覆盖);
如需恢复其本地仓库,把 `归档/内嵌git-20261008/` 里的 `.git` 挪回原处即可。
This commit is contained in:
admin committed 2026-10-08 22:29:52 +08:00
1 parent e03465c398
commit 237a09a5b0
161 files changed
+19429 -2

No files matched your search

+232
View File
@@ -0,0 +1,232 @@
from __future__ import annotations
import importlib.util
import subprocess
import sys
import unittest
from argparse import Namespace
from pathlib import Path
MODULE_PATH = Path(__file__).resolve().parents[1] / "scripts" / "motion_budget.py"
SPEC = importlib.util.spec_from_file_location("motion_budget", MODULE_PATH)
assert SPEC and SPEC.loader
MOTION_BUDGET = importlib.util.module_from_spec(SPEC)
sys.modules[SPEC.name] = MOTION_BUDGET
SPEC.loader.exec_module(MOTION_BUDGET)
def arguments(**overrides: object) -> Namespace:
values: dict[str, object] = {
"frames": 96,
"display": (240, 240),
"dpr": 1.0,
"max_texture": 4096,
"driver": "pointer",
"time_control": "scrub",
"parameter_space": "circular",
"access": "auto",
"background_owner": "page",
"atlas_max_memory_mib": 192.0,
"linear_video_min_frames": 180,
"source": None,
"cell": None,
"scroll_pages": None,
"frames_per_page": 24.0,
}
values.update(overrides)
return Namespace(**values)
class MotionBudgetSelectionTests(unittest.TestCase):
def test_cli_requires_explicit_background_owner(self) -> None:
completed = subprocess.run(
[
sys.executable,
str(MODULE_PATH),
"--frames",
"240",
"--display",
"1280x720",
"--strict",
],
capture_output=True,
text=True,
)
self.assertNotEqual(completed.returncode, 0)
self.assertIn("--background-owner", completed.stderr)
def test_small_random_sequence_selects_alpha_atlas(self) -> None:
report = MOTION_BUDGET.build_report(arguments())
self.assertEqual(report["delivery"]["selected"], "alpha-atlas")
self.assertEqual(report["runtime"]["renderer"], "css-alpha-atlas")
self.assertEqual(report["runtime"]["controller"], "frame-scrub")
self.assertTrue(report["passes"])
def test_large_circular_sequence_falls_back_to_chroma_video(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=48,
display=(640, 640),
parameter_space="circular",
)
)
self.assertEqual(report["texture"]["columnsPerSheet"], 6)
self.assertEqual(report["texture"]["rowsPerSheet"], 6)
self.assertEqual(report["texture"]["framesPerSheet"], 36)
self.assertEqual(report["texture"]["sheetCount"], 2)
self.assertEqual(report["delivery"]["selected"], "chroma-video")
self.assertIn(
"atlas-budget-exceeded",
report["delivery"]["reasonCodes"],
)
self.assertTrue(report["passes"])
def test_large_linear_scroll_selects_chroma_video(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=551,
display=(1536, 864),
driver="scroll",
parameter_space="linear",
)
)
self.assertEqual(report["delivery"]["selected"], "chroma-video")
self.assertEqual(report["runtime"]["renderer"], "webgl-chroma-video")
self.assertEqual(report["runtime"]["controller"], "frame-scrub")
self.assertIn("long-linear-sequence", report["delivery"]["reasonCodes"])
self.assertTrue(report["passes"])
def test_two_dimensional_input_is_never_flattened_to_video(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=400,
display=(900, 900),
parameter_space="2d",
)
)
self.assertEqual(report["delivery"]["selected"], "alpha-atlas")
self.assertIn(
"two-dimensional-parameter-needs-discrete-frames",
report["delivery"]["reasonCodes"],
)
self.assertTrue(
any(
"拆分参数轴" in failure and "用户确认" in failure
for failure in report["failures"]
)
)
self.assertFalse(report["passes"])
def test_discrete_states_are_split_instead_of_flattened(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=400,
display=(900, 900),
driver="state",
parameter_space="discrete",
)
)
self.assertEqual(report["delivery"]["selected"], "alpha-atlas")
self.assertIn(
"discrete-states-need-independent-assets",
report["delivery"]["reasonCodes"],
)
self.assertFalse(report["passes"])
def test_baked_scene_video_when_background_belongs_to_video(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=551,
display=(1536, 864),
driver="scroll",
parameter_space="linear",
background_owner="video",
)
)
self.assertEqual(report["delivery"]["selected"], "baked-video")
self.assertEqual(report["runtime"]["renderer"], "baked-video")
self.assertEqual(report["runtime"]["controller"], "frame-scrub")
self.assertIn(
"background-baked-into-video",
report["delivery"]["reasonCodes"],
)
self.assertIn("long-linear-sequence", report["delivery"]["reasonCodes"])
self.assertEqual(report["backgroundOwner"], "video")
self.assertTrue(report["passes"])
def test_scroll_segment_play_is_not_misclassified_as_scrub(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=240,
display=(1280, 720),
driver="scroll",
time_control="segment-play",
parameter_space="linear",
background_owner="video",
)
)
self.assertEqual(report["delivery"]["selected"], "baked-video")
self.assertEqual(report["runtime"]["controller"], "segment-playback")
self.assertEqual(report["access"], "sequential")
def test_cli_requires_explicit_time_control(self) -> None:
completed = subprocess.run(
[
sys.executable,
str(MODULE_PATH),
"--frames",
"240",
"--display",
"1280x720",
"--background-owner",
"video",
],
capture_output=True,
text=True,
)
self.assertNotEqual(completed.returncode, 0)
self.assertIn("--time-control", completed.stderr)
def test_baked_video_is_not_failed_by_atlas_budget(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=900,
display=(900, 900),
parameter_space="circular",
background_owner="video",
)
)
self.assertEqual(report["delivery"]["selected"], "baked-video")
self.assertTrue(report["passes"])
def test_baked_video_rejects_flattened_two_dimensional_input(self) -> None:
report = MOTION_BUDGET.build_report(
arguments(
frames=400,
display=(900, 900),
parameter_space="2d",
background_owner="video",
)
)
self.assertEqual(report["delivery"]["selected"], "baked-video")
self.assertIn(
"baked-video-needs-independent-clips",
report["delivery"]["reasonCodes"],
)
self.assertFalse(report["passes"])
if __name__ == "__main__":
unittest.main()