Newshot
Account

Show HN:Zipzi——开源的 Live2D 编辑器替代方案,支持 AI 辅助编辑

Translation(model translation, not the source's own text)

Zipzi 2D

English · 简体中文 · 日本語

一个与 AI 协作创作的开源 2D 建模与动画工具。

你来塑造画面。你的 AI agent 协助完成建模工作。Zipzi 将可视化桌面编辑器与 Python API 相连,因此你和你的 agent 可以查看并编辑同一个模型,共享撤销历史,并在彼此的修改基础上继续构建。

Zipzi 2D 是 Live2D Cubism Editor 的开源替代品,使用 Rust 和 GPUI 构建。其名称来自粤语 摺紙(zip3 zi2),意为“折纸”。

下载 Alpha · Python SDK · 报告问题 · 参与贡献

Zipzi 2D 编辑器展示建模工作区
Zipzi 2D 编辑器展示建模工作区
早期开发阶段:目前尚无稳定版本。API 和文件格式可能会发生变化。编辑器支持 macOS 和 Windows。
  • 开源且可商用 — 使用开源编辑器和 MIT 许可的 SDK 创作、完善你的模型并将其用于商业用途。
  • 原生且高性能 — 使用 Rust 和 GPUI 构建,内存占用低、编辑响应流畅,即使面对复杂模型和密集网格也是如此。
  • 面向 agent — 从零开始创作、与 AI 协作,或导入现有模型进一步完善。

你的编辑器。你的 AI agent。同一个模型。

向你的 AI 编程 agent 描述你想要的效果。它使用 Python SDK 查看模型、渲染图像并进行修改,你可以在编辑器中审阅并撤销这些修改。你和你的 agent 操作同一个文档,共享撤销历史。

自带具备 Python 能力的 agent,并让它查阅 SDK 指南。

第一段代码:让 AI 为每个网格赋予有意义的名称

你描述任务;你的 AI agent 编写并运行代码。以下示例由 AI 编程 agent 生成,并针对运行中的 Editor 进行了测试。它们展示了 agent 如何通过 Python SDK 工作——你无需自己编写这些脚本。你的职责是说明你想要什么,并在编辑器中审阅结果。

对你的 agent 说:“查看每个网格,并为它赋予一个有意义的名称。”

安装 Python 客户端(CPython 3.14),启动一个支持 GPU 观测的兼容 Editor,并打开一个模型。具备图像能力的编程 agent 可以执行以下两步。

  1. agent 观察每一个网格。它生成的脚本为每个网格导出一张图像,在带纹理的模型上高亮显示其线框,并附上一份 JSON 命名词表。observe 提供视觉证据;agent 提供语义解读。

        import json
from pathlib import Path
from uuid import uuid4

import zipzi
from zipzi import inspection, observation, spatial

output = Path("mesh-review-" + uuid4().hex[:8]).resolve()
output.mkdir()

with zipzi.connect() as runtime:
    sessions = runtime.sessions.list()
    if len(sessions) != 1:
        raise RuntimeError("Open exactly one model for this example.")
    session = runtime.sessions.attach(sessions[0].id)

# Follow every page: a single list() call may not contain all meshes.
    meshes, cursor, source = [], None, None
    while True:
        page = session.meshes.list(cursor=cursor)
        if source is None:
            source = page.source
        if page.source != source:
            raise RuntimeError("Model changed; restart the inspection.")
        meshes.extend(page.items)
        cursor = page.next_cursor
        if cursor is None:
            break
      

Show HN: Zipzi – 开源 Live2D 编辑器替代方案,支持 AI 辅助编辑


        rows = []
    for index, mesh in enumerate(meshes):
        # Use this mesh's bounds to frame it, including hidden geometry.
        # {} evaluates default parameter values, not the editor's current pose.
        query = spatial.Bounds(
            targets=(spatial.MeshTarget(value=mesh.id),), include_hidden=True,
        )
        bounds = session.modeling.spatial(
            ({},), (query,), expected=source,
        ).wait().value.frames[0].results[0].value.model_bounds
        row = dict(id=mesh.id, old_name=mesh.name, new_name=mesh.name, image=None)
        if bounds is not None:
            x0, y0, x1, y1 = bounds
            margin = max(x1 - x0, y1 - y0, 1.0) * 0.15
            view = observation.View(
                width=768, height=768,
                roi=(x0 - margin, y0 - margin, x1 + margin, y1 + margin),
                topology=observation.Overlay(
                    targets=(observation.MeshTarget(value=mesh.id),),
                    wireframe=True, include_hidden=True,
                ),
            )
            # Freeze all observations to the inventory's source. If the model
            # changes, the SDK refuses stale reads; rerun instead of mixing them.
            images = session.modeling.observe(({},), view, expected=source).wait()
            report = inspection.save(images, output / f"mesh-{index:04d}")
            row["image"] = str(report.images[0])
        rows.append(row)

# SessionId is a typed handle: store its fields for the second script.
    worksheet = output / "names.json"
    worksheet.write_text(json.dumps(
        dict(session_id=dict(runtime=session.id.runtime, serial=session.id.serial),
             meshes=rows), indent=2, ensure_ascii=False,
    ), encoding="utf-8")
    print(worksheet)
      

让 agent 打开每个导出的 PNG,在上下文中识别被高亮的 mesh,并且只修改 names.json 中的 new_name。保持 ID 和 old_name 不变。叠加层选中的是用于诊断的几何体,而非孤立的图稿:周围纹理仍然可见,隐藏或被遮挡的图稿仍可能难以判断。对于不确定或没有图像的条目,保留原始名称;或者先检查更多姿势,再进行命名。

  1. agent 统一应用这些语义名称。在你审查了建议的名称之后,agent 会编写并运行以下脚本,并传入 names.json 的路径。你无需复制代码或运行终端命令。在检查与应用之间,保持同一个模型处于打开且未更改的状态。

        import json
import sys
from pathlib import Path

import zipzi

review = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
rows = review["meshes"]
if len({row["id"] for row in rows}) != len(rows):
    raise ValueError("Duplicate mesh IDs in the worksheet.")
if any(not isinstance(row["new_name"], str) or not row["new_name"].strip()
       for row in rows):
    raise ValueError("Every mesh needs a nonempty name.")

with zipzi.connect() as runtime:
    # Rebuild the typed handle; a restarted Editor requires a new inspection.
    session = runtime.sessions.attach(zipzi.SessionId(**review["session_id"]))
    # All renames commit together as one undo step. A missing mesh or changed
    # original name aborts the edit instead of leaving a partly renamed model.
    with session.edit("AI: semantic mesh names") as edit:
        for row in rows:
            current = edit.meshes.get(row["id"]).value
            if current.name != row["old_name"]:
                raise RuntimeError("Mesh changed; inspect the model again.")
            if row["new_name"] != row["old_name"]:
                edit.meshes.rename(
                    row["id"], row["new_name"], expected_name=row["old_name"],
                )
    print("Review the names in the editor. Undo to revert, or save to keep them.")
      

项目不会自动保存。名称检查会检测被重命名或移除的网格,而不是所有可能的几何或纹理变更;如果模型已更改,请重复检查。更多工作流请参阅功能指南。

也为动手创作而构建

使用网格、参数、变形器和 BlendShapes,然后在动画工作区中将它们组合起来。生成网格几何体或手动细化它。Mesh Edit 允许你处理已摆好姿势的模型,或切换到源图像,同时在几何变化时重新采样已存储的形状。

Python 脚本还可以通过本地 Runtime 独立运行,用于编辑器之外的自动化。探索 Python SDK,以进行建模、动画创作、预览和检查。

试用 Zipzi 2D

  • 使用编辑器:从 GitHub Releases 下载 Alpha 构建。查看发布说明,了解可用的平台构建和要求。
  • 使用 Python 自动化:遵循安装和连接指南。SDK 当前需要 CPython 3.14。
  • 构建你自己的工具:探索 Rust SDK 以
变更区域起始命令
单个 Rust crate/模块cargo test --locked -p <crate> --lib <filter> ; 在相关时添加其集成目标
运行时所有权/作业/事件./tools/test-sdk.sh runtime
本地协议 / 已安装的 Python 客户端./tools/test-sdk.sh python-connected
SDK 创作行为./tools/test-sdk.sh fast <filter>
编辑器自适应网格生成./tools/test-editor.sh fast adaptive_mesh:: ; ./tools/test-editor.sh fast mesh_generation::
SDK alpha 网格生成./tools/test-sdk.sh mesh
wgpu 后端 / 本地 GPU 一致性cargo test --locked -p zipzi-render-wgpu --tests ; 主机选择
编辑器协调./tools/test-editor.sh fast <filter>
编辑器 UI(macOS/Metal)./tools/test-editor.sh ui <filter>
运行时 Python SDK( zipzi-python )、本地/已连接及类型./tools/test-sdk.sh python ( scope )
共享创作契约 / 隔离的 Python 生成cargo test --locked -p zipzi-contract ; uv run --locked python tools/test_tools.py -p test_python_codegen.py
运行时 GPU 观察 / 检查(需要可用的 GPU)./tools/test-sdk.sh python --observation
Python 完整调用恢复、编辑状态和作业超时./tools/test-sdk.sh python --recovery (optional P3ARecovery.test_name )
Python 集合页面、会话分离/关闭和离线目录./tools/test-sdk.sh python --discovery
已安装的新客户端、主机发现和会话绑定./tools/test-sdk.sh python-connected (optional --editor-host /absolute/path/to/zipzi-editor )
仓库工具uv run --locked python tools/test_tools.py -p test_<tool>.py

过滤器和文件名是占位符;省略它们即可运行所选门禁。对于 crate 的集成目标,请查看其 README 和 tests/,或使用 cargo test --locked -p <crate> --test <target> -- --list 列出用例。编辑器 shell 门禁会清除 ZIPZI_DEV_SESSION_DIR;直接运行编辑器 Cargo 测试时请显式清除它。

完整覆盖、前置条件和 CI 定义了回归、压力、原生验收和打包 wheel 门禁。未提供模式时,两个领域脚本默认执行开销较大的完整运行。普通 cargo test 仅选择 zipzi-core、zipzi-project 和 zipzi-sdk。工具测试应放在 tools/tests/,crate 测试留在各自 crate 内,共享数据应放在 fixtures/。

所有自有 crate 共享根 Cargo 工作区和锁文件。本地模型应放在 models/local/;参见模型清单。源码归档、Python wheel 和 macOS 应用包有单独的发布检查。

许可证与第三方权利

SDK 组件使用 MIT;编辑器组件使用 GPL-3.0-only。LICENSING 标识范围与共享文件来源;第三方声明保留依赖和基准测试例外。

Live2D、Cubism、Live2D Cubism SDK、Cubism Core、Cubism Native Framework 及相关示例数据归 Live2D Inc. 和/或其各自权利人所有,或经其许可。本项目独立,与 Live2D Inc. 无关联,也未获其授权、认可或赞助。“Live2D”和“Cubism”这两个名称仅用于描述互操作性。

本仓库不分发专有的 Cubism Core 二进制文件、Cubism SDK 包或 Live2D 示例模型资产。获取、构建、链接、发布或分发使用 Live2D 材料的软件的用户,有责任遵守所有适用条款,包括 Live2D Proprietary Software License Agreement、Live2D Open Software License Agreement 以及任何适用的示例数据条款。本仓库的 MIT 许可证不授予第三方软件、模型、美术作品、商标或其他材料的任何权利。

The translation is machine-generated and individual terms may be off. Nothing is rewritten or cut; the original is authoritative.

Published by HN AI
This site only summarises and aggregates; copyright stays with the original author. Headlines and summaries follow the source — where they differ, the original wins.
Read the original ↗