将 CycleGUI 开发技能(含 Duplicated id 防碰撞规范)纳入 .cursor/skills,并调整 gitignore 仅放行 skills 目录可提交。 Co-authored-by: Cursor <cursoragent@cursor.com>
21 KiB
CycleGUI API 参考
颜色字段统一为
System.Drawing.Color(2026-05 改造):所有公开 API 的 color/colors/_shine/_border_color/team_color/shine_color 字段都是Color,不再有uint入口。详见SKILL.md## 颜色契约章节。如果你拿到的是引擎 wire-formatuint(bit0..7=R),用Extensions.FromRgba8(uint)升回Color;System.Drawing ARGB 布局(0xAARRGGBB)则用Color.FromArgb(unchecked((int)argb))。
PanelBuilder 控件完整签名
维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\PanelBuilder.Controls.cs
布局
void Label(string text)
void Separator()
void SeparatorText(string text)
void SameLine(int spacing = 0)
void CollapsingHeaderStart(string label) // 必须与 End 配对;不可嵌套
void CollapsingHeaderEnd()
CycleGUI 没有
BeginChild/ChildWindow/BeginTabBar/BeginTabItem。容器分区用Table(height:)+CollapsingHeader;Tab 切换用TabButtons(见下方"列表与选择")。
按钮与切换
// 返回 true 表示被点击
bool Button(string text, string shortcut = "", string hint = "", string distinct = "", bool disabled = false)
// 弹出菜单按钮
void PopMenuButton(string buttonTxt, MenuItem[] menu, Action clickBtn = null)
// 按钮组,返回 true 表示有选择,selecting 为选中索引
bool ButtonGroup(string prompt, string[] buttonText, out int selecting, bool sameLine = false)
// 复选框,返回 true 表示值改变
bool CheckBox(string desc, ref bool chk)
// 开关,返回 true 表示值改变
bool Toggle(string desc, ref bool on)
// 单选按钮,返回 true 表示选择改变
bool RadioButtons(string prompt, string[] items, ref int selected, bool sameLine = false)
输入
// 文本输入。ret 为当前文本,doneInput 为 true 表示按下回车
(string ret, bool doneInput) TextInput(string prompt, string defaultText = "",
string hintText = "", bool focusOnAppearing = false,
bool hidePrompt = false, bool alwaysReturnString = false)
数值控件
bool DragFloat(string prompt, ref float valf, float step,
float min = float.MinValue, float max = float.MaxValue, bool disableCache = false)
bool SliderInt(string prompt, ref int val, int min, int max, bool disableCache = false)
bool SliderFloat(string prompt, ref float val, float min, float max, bool disableCache = false)
bool DragVector2(string prompt, ref Vector2 vector, float step = 0.01f,
float min = float.MinValue, float max = float.MaxValue)
bool DragMatrix(int m, int n, float[] vals)
bool BezierEditor(string prompt, ref Vector4 controlPoints, ref float startY, ref float endY)
颜色
bool ColorEdit(string label, ref Color color, bool alphaEnabled = true)
列表与选择
// 返回选中索引,-1 无选择
int ListBox(string prompt, string[] items, int height = 5,
bool persistentSelecting = false, int preselected = -1)
bool DropdownBox(string prompt, string[] items, ref int selected)
// 返回选中标签页索引
int TabButtons(string prompt, string[] items, int forceSelect = -1)
forceSelect:希望激活的标签页索引(0-based);-1 不强制。API 内建变化检测:仅当该值相对上次变化时才下发 ImGuiTabItemFlags_SetSelected,调用方可每帧传入当前目标 Tab,无需自己做 one-shot 门控。用户手动切换 Tab 后,只要 forceSelect 不变就不会再被拉回。
表格
unsafe void Table(string strId, string[] header, int rows,
Action<Row, int> content, int height = 0,
bool enableSearch = false, string title = "",
bool freezeFirstCol = false, int scrollToRow = -1,
Action<int, bool>? onHeaderSort = null)
height:可见数据行数;<=0 表示不限制高度、显示全部行。scrollToRow:希望滚动到可见的数据行索引(0-based);-1 不滚动。API 内建变化检测:仅当该值相对上次变化时才下发 ImGui::SetScrollHereY,调用方可每帧传入当前选中行,用户之后可自由滚动列表。传入 -1 会复位持久态,便于「取消选中后再选同一行」能重新触发滚动。
Row 对象可用方法:Label, ButtonGroup, Checkbox, SetColor, Image
图表
// 实时折线图,返回可选按钮索引
int RealtimePlot(string prompt, float val, bool freeze = false, string[] optionalButtons = null)
// 迷你指标
bool MiniPlot(string name, float value)
bool MiniPlot(string name, string value)
bool MiniPlot<TEnum>(string name, TEnum value) where TEnum : Enum
// 静态折线图
void Plot2D(string prompt, float[] vals, int height = 200)
// ⚠️ 以下为占位/空壳(源码 body 为空,调用无效果,请勿依赖):
// Progress, BulletText, Indent / UnIndent, QuestionMark, ToolTip
// - 需要进度展示:用 RealtimePlot 或 Label 渲染百分比
// - 需要 tooltip:用 Button(hint:) / Table.Row.Label(hint:) 等已实现的入口
void Progress(float val, float max = 1) // 空壳,无效果
图像
void Image(string prompt, string rgba, int height = -1)
// 图像列表,返回选中索引
int ImageList(string prompt, (string rgba, string top_title, string bottom_title)[] items,
bool persistentSelecting = false, int height_px = 100,
bool hideSeparator = false, int selecting = -1)
聊天框
(bool ret, string sending) ChatBox(string prompt, string[] appending,
int lines = 18, bool input = true)
文本展示
void SelectableText(string prompt, string content, bool copyButton = true)
文件对话框
bool OpenFile(string prompt, string filters, out string dir, string defaultFn = "")
bool SaveFile(string prompt, string filter, out string dir, string defaultFn = "")
bool SelectFolder(string prompt, out string dir)
Web 与链接
void OpenWebview(string name, string url, string hint = "")
void DisplayFileLink(string localfilename, string displayName)
菜单栏
void MenuBar(List<MenuItem> menu)
MenuItem 构造:
new MenuItem(string label, Action onClick = null, string shortcut = null,
bool selected = false, bool enabled = true, List<MenuItem> subItems = null)
// label = "-" 表示分隔线
面板控制
bool Closing() // 返回 true 表示用户点击关闭或终端断开
void DelegateUI() // 执行通过 Panel.dels 注入的委托 UI
Panel 配置方法
维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\Panel.cs
Panel ShowTitle(string title) // null 隐藏标题栏
Panel InitSize(int w = 320, int h = 240)
Panel FixSize(int w, int h) // 固定不可调整大小
Panel AutoSize(bool set)
Panel InitPos(bool pin, int left, int top,
float myPivotX = 0, float myPivotY = 0,
float screenPivotX = 0, float screenPivotY = 0)
Panel InitPosRelative(Panel panel, int left, int top,
float relPivotX = 0, float relPivotY = 0,
float myPivotX = 0, float myPivotY = 0)
Panel SetDefaultDocking(Docking docking, bool auxiliary = false)
Panel Modal(bool set)
Panel TopMost(bool set)
Panel AsToolbarPanel(int height = 38, ToolbarAnchor anchor = ToolbarAnchor.RightTop)
枚举:
Panel.Docking:Left,Top,Right,Bottom,None,FullPanel.ToolbarAnchor:RightTop,LeftBottom
实例方法:
void Define(CycleGUIHandler handler)
void Repaint(bool dropCurrent = false, int repaintTimeMs = 30)
// dropCurrent=true:丢弃当前帧,立即重绘(编辑后同步 UI 时用)
// repaintTimeMs:持续 Repaint 时的间隔,默认 30ms
// 只在有实时数据的面板持续调用;静态面板不要无条件 Repaint
void BringToFront()
void Exit()
void Freeze() / void UnFreeze()
void SwitchTerminal(Terminal newTerminal)
bool Probe<T>(CycleGUIProber<T> prober, out T val)
void FireAndForget(...)
HoverMenu
维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\API\HoverMenu.cs
HoverMenu GUI.DeclareHoverMenu()
enum HoverMenuPlacement {
Cursor = 0,
ObjectScreenAnchor = 1, // 默认;使用 hovered object 的屏幕投影锚点
ObjectBounds = 2, // 预留,v1 不支持
}
class HoverMenu : IDisposable {
string Name { get; set; }
string TargetObjectName { get; set; }
HoverMenuPlacement Placement { get; set; } // 默认 ObjectScreenAnchor
int OffsetX { get; set; } // 默认 12
int OffsetY { get; set; } // 默认 12
int CloseDelayMs { get; set; } // 默认 180
PanelBuilder.CycleGUIHandler Build { get; set; }
Terminal Terminal { get; }
void Start()
void StartOnTerminal(Terminal terminal)
void Stop()
void Dispose()
}
实现语义:每个 terminal 一个 manager/native listener,同一时间复用一个 transient panel;C# 侧按 TargetObjectName 字典匹配,暂假设一个 object 一个 HoverMenu,重复注册同一 object 会抛异常。native feedback 按 hovered object、object anchor、dragging 去重,不按鼠标移动持续推送。
Workspace Props 完整列表
维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\API\Workspace.Props.cs
模型
// 加载 GLTF 模型类(不可 Remove)
LoadModel { name, detail: ModelDetail }
// ModelDetail 结构
ModelDetail(byte[] gltfBytes) {
Center = Vector3,
Rotate = Quaternion,
Scale = float,
ColorBias = Vector3,
ColorScale = float,
Brightness = float,
ForceDblFace = bool,
NormalShading = float,
}
// 更新已加载模型的参数(不重新传 GLTF 数据)
ReloadModel { name, detail: ModelDetail }
// 放置模型实例
PutModelObject { name, clsName, newPosition: Vector3, newQuaternion: Quaternion, baseColor?: Color /* 预留,引擎当前忽略 */ }
// 自定义网格
DefineMesh { clsname, positions: float[] /* 三角面顶点,长度必须是9的倍数 */, color: Color, smooth: bool }
点云
PutPointCloud {
name: string,
xyzSzs: Vector4[], // xyz + size
colors: Color[], // 每点一个 System.Drawing.Color
newPosition: Vector3,
newQuaternion: Quaternion,
handleString: string, // 空=无句柄, 单字符=字符句柄, 多字符=PNG图标
type: int, // 0=普通, 1=SLAM地图
}
线和曲线
PutStraightLine {
name, start: Vector3, end: Vector3,
propStart: string, propEnd: string, // 绑定到对象(空则用 start/end)
arrowType: Painter.ArrowType, width: int, color: Color, dashDensity: int,
}
PutBezierCurve {
name, start: Vector3, end: Vector3,
control1: Vector3, control2: Vector3,
width: int, color: Color,
}
PutVector { name, from: Vector3, dir: Vector3, color: Color, length: int }
图像与纹理
// 静态图像
PutImage { name, rgbaName, displayType, displayH, displayW, /* transform fields */ }
// 可更新 RGBA 纹理
PutRGBA { name, width, height, requestRGBA / rgba }
.StartStreaming() -> Action<byte[]> // 返回更新函数
.Invalidate()
.UpdateRGBA(byte[])
// SVG
DeclareSVG { name, svgContent: string }
对象操作
// 变换对象位置/旋转
TransformObject { name, pos: Vector3, quat: Quaternion, timeMs: int, coord: Coord }
// Coord: Absolute / Relative
// 变换子对象
TransformSubObject { objectNamePattern, subObjectName/subObjectId, translation, rotation, timeMs }
// 对象锚定(moon 跟随 earth)
SetObjectMoonTo { name: "moon", earth: "earth_obj", pos: Vector3, quat: Quaternion }
// 删除对象(通配符)
WorkspaceProp.RemoveNamePattern(string namePattern) // 支持 * 和 ?
文本与图标
PutHandleIcon { name, ... }
PutTextAlongLine { name, ... }
SpotText { /* fluent builder */ }
高斯溅射(Gaussian Splatting)
PutGaussianSplats {
name, splats: GaussianSplat[],
globalOpacityScale, globalSizeScale, renderMode, ...
}
PutGaussianSplats.FromPLY(path, name, axisPreset)
PutGaussianSplats.FromPointCloud(...)
PutGaussianSplats4D { /* 4D 时序数据 */ }
Workspace UI 操作
维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\API\Workspace.UIOps.cs
相机
SetCamera {
lookAt: Vector3,
azimuth: float, // 默认 -PI/2
altitude: float, // 默认 PI/2
distance: float,
fov: float,
projectionMode: Perspective / Orthographic,
displayMode: Normal / VR / EyeTrackedHolography / EyeTrackedLenticular,
anchor_type: Both / StareOnly / PositionOnly / CopyCamera,
azimuth_range: Vector2, // 限制旋转范围
altitude_range: Vector2,
pan_range: Vector3, // 限制平移范围
mmb_freelook: bool, // 中键自由视角
}
// 提交方式:.IssueToDefault() / .IssueToAllTerminals() / .IssueToTerminal(t)
外观
SetAppearance {
useEDL: bool, // Eye-Dome Lighting
useSSAO: bool, // 环境光遮蔽
useGround: bool, // 地面
useBorder: bool, // 边框
useBloom: bool, // 泛光
drawGroundGrid: bool, // 地面网格
drawGuizmo: bool, // 坐标轴指示器
useDefaultSky: bool, // 默认天空盒
sun_altitude: float, // 太阳高度
hover_shine: Color, // 悬停高亮色
selected_shine: Color, // 选中高亮色
hover_border_color: Color,
selected_border_color: Color,
world_border_color: Color,
voxel_quantize: float, // 体素量化
voxel_opacity: float, // 体素不透明度
clippingPlanes: (Vector3 center, Vector3 direction)[], // 最多4个裁剪面
bring2front_onhovering: bool,
}
对象外观
SetObjectApperance { namePattern, bring_to_front, shine_color: Color, use_border, transparency }
SetModelObjectProperty { namePattern, baseAnimId, nextAnimId, material_variant, team_color: Color,
base_stopatend, next_stopatend, animate_asap }
SetPropShowHide { namePattern, show: bool } // sticky pattern (2026-05+)
SetPropApplyCrossSection { namePattern, apply: bool } // sticky pattern (2026-05+)
Sticky pattern 语义(适用于
SetPropShowHide/SetPropApplyCrossSection/SelectObject.SetObjectSelectable/SelectObject.SetObjectSubSelectable):每次调用先按 pattern 扫一遍global_name_map立即生效,同时把 pattern 字符串记入当前 viewport 的workspace_state.*_patterns。之后Workspace.AddProp加入的新对象会被引擎在indexier::add自动按 memo 重匹配并设位/隐藏/纳入 selectables。要取消粘性,用同一 pattern 字符串反向调 一次(SetPropShowHide{show=true}/SetObjectUnselectable(pattern)等)。Pattern 是 glob(
*/?),引擎全栈唯一语义。底层是libVRender::wildcardMatch, 2026-05 统一化后已删除RegexMatcher::match/regexMatch全套 regex 路径。详见 SKILL.md 的## namePattern 语法 = glob章节,那里有完整的 API 列表 + 历史根因 + "真要 regex 怎么办" 指引。
交互操作
所有交互操作继承 WorkspaceUIOperation<T>,通过 .Start() 启动,.End() 结束,.feedback 回调接收结果。
// 拾取世界坐标
GetPosition {
method: PickMode.GridPlane / Holo3D,
snaps: string[], // 可吸附对象名
}
// feedback: Action<WorldPosition, op>
// WorldPosition { mouse_pos, snapping_object, object_pos, sub_id }
// 拖拽跟随
FollowMouse {
method: FollowingMethod.LineOnGrid / RectOnGrid / PointOnGrid / CircleOnGrid / Line3D / ...,
follower_objects: string[],
start_snapping_objects: string[],
end_snapping_objects: string[],
realtime: bool,
}
// feedback: Action<FollowFeedback, op>
// 对象选择
SelectObject {
fineSelectOnPointClouds: bool,
fineSelectOnHandle: bool,
}
// feedback: Action<(string name, BitArray selector, string firstSub)[], op>
// feedback 返回的是“当前完整选中集”(不是 delta),由引擎处理 Shift+加选 / Alt+减选 / 框选
// 运行时切换模式:selectOp.SetSelectionMode(SelectionMode.Rectangle, paintRadius)
// SelectionMode: Click / Rectangle / Paint
//
// SetObjectSelectable(pattern) / SetObjectSubSelectable(pattern)
// - pattern 是 glob:"*" = 任意子串、"?" = 任意单字符;不是 ECMAScript 正则
// - 立即对已存在对象按 glob 设可选位
// - 并把 pattern 记入 workspace_state.selectable_patterns(sticky,2026-05 起)
// - 之后 AddProp 加入的新对象会被引擎自动匹配 + 设位(indexier::add hook)
// - 取消 sticky:用同一 pattern 调 SetObjectUnselectable / SetObjectSubUnselectable
// Guizmo 操作(移动/旋转 gizmo)
GuizmoAction {
dof: GuizmoDof, // 默认 TranslateXYZ
realtimeResult: bool,
}
// GuizmoDof: None, TranslateX/Y/Z, RotateX/Y/Z, Roll, Pitch, Yaw,
// TranslateXYZ, RotateXYZ, PlanarXY, PlanarXYYaw, All
// feedback: Action<(string name, Vector3 pos, Quaternion rot)[], op>
// 原始鼠标事件
RegisterMouseAction {
listen_MouseDown, listen_MouseUp, listen_MouseMove, listen_Wheel: bool,
}
// feedback: Action<MouseAction, op>
// MouseAction { mouseX, mouseY, workspaceX, workspaceY, mouseLB/RB/MB, wheelDelta }
工作区行为
SetWorkspaceBehaviour {
operation_trigger: Mouse.MouseLB, // 操作触发键
workspace_pan: Mouse.MouseRB, // 平移键
workspace_orbit: Mouse.MouseMB, // 旋转键
}
// Mouse: MouseLB, MouseMB, MouseRB, CtrlMouseLB, CtrlMouseMB, CtrlMouseRB
查询操作
// 查询视口相机状态
new QueryViewportState { callback = state => {
// state.CameraPosition, state.LookAt, state.Up
}}.IssueToDefault();
// 捕获渲染画面
new CaptureRenderedViewport { callback = img => {
// img.bytes (RGB), img.width, img.height
}}.IssueToDefault();
// 查询图形信息
new QueryGraphics { callback = state => {
// state.MonitorCount, state.Monitors[], state.FPS
}}.IssueToDefault();
// 聚焦到对象
new FrameToFit { name = "objectName", margin = 1.1f }.IssueToDefault();
// 全屏
new SetFullScreen { fullscreen = true, screen_id = -1 }.IssueToDefault();
// 自定义网格
new SetOperatingGridAppearance {
show = true, pivot = Vector3.Zero,
unitX = Vector3.UnitX, unitY = Vector3.UnitY,
}.IssueToDefault();
// ImGui 样式
new SetImGUIStyle {
windowBg = 0xFF171717, button = 0xFF3D3835,
windowRounding = 6f, frameRounding = 6f,
}.IssueToDefault();
// 主窗口菜单栏
new SetMainMenuBar {
menu = new List<MenuItem> { ... }, show = true
}.IssueToDefault();
// Viewport 专属菜单栏
var viewport = GUI.PromptWorkspaceViewport();
new SetWorkspaceMenuBar {
viewport = viewport,
menu = new List<MenuItem> { ... }, show = true
}.Issue();
// 面板持久菜单栏(从 handler 外部设置,自动注入到每次重绘)
new SetPanelMenuBar {
panel = myPanel,
menu = new List<MenuItem> { ... }
}.Issue();
// 清除:new SetPanelMenuBar { panel = myPanel, menu = null }.Issue();
Painter 完整 API
维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\Painter.cs
// 获取/创建命名 Painter(单例)
static Painter GetPainter(string name)
// 清除当前帧数据(双缓冲交换)
void Clear()
// 绘制点(单位:米)
void DrawDot(Color color, Vector3 xyz, float size = 1f)
// 绘制线段
void DrawLine(Color color, Vector3 start, Vector3 end,
float width = 1f, ArrowType arrow = ArrowType.None, int dashScale = 0)
// ArrowType: None, Start, End
// 绘制方向向量(像素长度)
void DrawVector(Vector3 from, Vector3 dir, Color color,
float width = 1f, int pixels = 10)
// 绘制 3D 文本
void DrawText(Color color, Vector3 tCenter, string s)
// 绘制区域体素
void DrawRegion3D(Color color, Vector3 center)
// 绘制填充多边形(2D 点 + 3D 变换)
void DrawPolygonFilled(Vector2[] points2D, Vector3 trans, Quaternion quat,
Color borderColor, Color fillColor, float thickness = 0f)
// thickness=0: 平面多边形; >0: 拉伸立体
// 终端隔离
Painter.terminal = specificTerminal; // null 则广播到所有终端
LeastServer(HTTP/WebSocket 服务)
全局类(无命名空间),维护者核对路径:D:\MDCS\Source\Core\CycleGUI\CycleGUI\Terminals\LeastServer.cs
static void Listener(int port) // 阻塞式启动监听
static void AddGetHandler(string path, Func<string> handler)
static void AddPostTextHandler(string path, Func<string, string> handler)
static void AddPostByteHandler(string path, Func<byte[], byte[]> handler)
static void AddServingFiles(string urlPrefix, string localPath)
static void AddServingResources(string urlPrefix, Assembly, string ns)
static void AddSpecialTreat(string path, Action<...> handler) // WebSocket 升级
Viewport(面板内嵌 3D 视口)
// 创建内嵌 Workspace 视口面板
var viewport = GUI.PromptWorkspaceViewport();
Viewport 继承 Panel,拥有独立的 ViewportSubTerminal,Workspace 状态与主终端隔离。