@easytwin/devkit 0.1.1 → 0.1.3

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.
@@ -5617,6 +5617,11 @@ interface EngineConfiguration {
5617
5617
  /** 是否启用ResourceManager持久化,默认false */
5618
5618
  enableResourcePersistence?: boolean;
5619
5619
  }
5620
+ /** 引擎每帧回调。由宿主注册,不要挂到 RuntimeEngine 实例方法上。 */
5621
+ type EngineTickListener = (engine: RuntimeEngine) => void;
5622
+ /** 在 updateScene 之后注册每帧回调。供 TwinApp 预览宿主使用,不是用户 SDK。 */
5623
+ declare function registerEngineTickListener(engine: RuntimeEngine, listener: EngineTickListener): void;
5624
+ declare function unregisterEngineTickListener(engine: RuntimeEngine, listener: EngineTickListener): void;
5620
5625
 
5621
5626
  declare const getDefaultEasyvEventListener: (comp: Component, overrrideParam?: Array<{
5622
5627
  name: string;
@@ -8240,4 +8245,4 @@ declare const MODEL_COMPONENT_TYPE = "Model";
8240
8245
  declare const SCENE_COMPONENT_TYPE = "Scene";
8241
8246
  declare const ID_PREFIX_COMP_VIRTUAL_CHILD = "compv";
8242
8247
 
8243
- export { AbstractManager, AbstractSceneManager, AddStateAction, AddVirtualChildAction, AlignmentAXIS, AnimationCurve, AnimationCurveExtrapolation, type AnimationCurveJson, AnimationModeEnum, type AnimationModeType, type AnimationModeValueType, type ArgumentMap, AssetLibraryManager, type AssetTypeToContentMap, BackInterpolant, BackInterpolationMode, BingMapsProvider, Blackboard, BounceInterpolant, BounceInterpolationMode, BoundingBox, BoxColliderObj, CSSRenderer, Camera, type CameraInfo, type CameraMode, CancelablePromise, CanvasUtils, CapsuleColliderObj, Cesium3DTilesetComponent, CharacterColliderObj, CharacterControllerComponent, CircularInterpolant, CircularInterpolantMode, ColliderColors, ColliderObj, CollisionDetectionMode, type Color, type ColorType, type ColorValueMap, Component, type ComponentCategory, type ComponentCtor, type ComponentJson, ComponentManager, ComponentRef, type ComponentSettings, type ComponentUI, type ComponentUI_Custom, type ComponentUI_Effect, type ComponentUI_Function, type ComponentUI_Scene, type ComponentWithRb, CompositeAction, ConsoleLogger, type ControlledModeEditorProps, CreateComponentAction, type CreateComponentParams, type CreateCustomComponentParams, type CreateEntityDto, CreateModelComponentAction, CubicInterpolant, CubicInterpolationMode, CustomComponentApi, type CustomComponentContent, type CustomComponentContextMenuItem, type CustomComponentEditors, type CustomComponentListItem, CustomComponentManager, type CustomComponentModule, DEFAULT_CHUNK_SIZE, type DebounceOptions, DebugProvider, type DecodedWebPAnimationFrame, type DisableSelectType, DoubleMap, DragPoint, type DrawPointMapType, DrawPointName, DrawPointSprite, DynamicRigidbodyComponent, DynamicRigidbodyConstraints, EasyTwinTween, type EasyvFilterAttributeParam, type EasyvSwitchStateAnimationParam, type EasyvSwitchStateParam, type EasyvUpdateCustomAttributeParam, type EditMode, EditModeAction, type EditorActionInfo, EditorActionsManager, type EditorComp, type EditorContext, EditorHelper, EditorPanelManager, type EditorProps, ElasticInterpolant, ElasticInterpolationMode, EngineCSSRenderObject, type EngineConfiguration, EngineCubicBezierCurve3, type EngineEmitFunc, EntityAPI, EntityUtil, type EventArgs, EventEmitter, type EventListener, type EventName, type EventNames, ExponentialInterpolant, ExponentialInterpolantMode, FeatImageExt, FeatModelExt, FeatVideoExt, FileApi, type FileChunk, FileTypeEnum, FileUtil, Fsm, FsmState, GROUP_COMPONENT_TYPE, type GeoLocation, GeoTransformForCenterAndNorthMode, GeoTransformForReferencePoints, type GeoTransformOptions, GeographicModule, Geolocation, GeolocationUtils, GoogleMapsProvider, type GradientColorValue, HeightDebugProvider, HereMapsProvider, type HierarchyConfig, HtmlEvent, type ICanAccessEngine, ID_PREFIX_COMP_VIRTUAL_CHILD, type IEditorAction, type IHierarchyNode, type ILogger, type IManager, type IModelLoader, type ISerializable, type ITextureLoader, type IVector2, IVector3, type IVector4, type InitStateDto, InputManager, type InspectorGroupKey, InterpMode, type Keyframe, Keys, type LCCLoadConfig, type LCCObject, type LCCRender, type LODControl, LODFrustum, LODRadial, LODRaycast, Linear2SRGB, LoadSceneMode, LoadState, LogLevel, Logger, MODEL_COMPONENT_TYPE, MapBoxProvider, MapComponent, MapHeightNode, MapHeightNodeShader, MapNode, MapNodeGeometry, MapNodeHeightGeometry, MapPlaneNode, MapProvider, MapSphereNode, MapSphereNodeGeometry, MapTilerProvider, MapView, type MaterialConfig, type MaterialInfo, MaterialPreviewRenderer, type MaterialTextureProperties, MaterialThumbnailGenerator, type MaterialUVProperties, ModalManager, type ModelInfo, ModelLoader, type ModelLoaderResult, ModelUtil, type MultiTypeColor, type Nullable, type NumberState, OBBHelper, ObjectTransformAction, OpenMapTilesProvider, OpenStreetMapsProvider, type PartialSome, PhysicsCombineMode, PhysicsControllerCollisionFlag, PhysicsControllerNonWalkableModeEnum, PhysicsShapeFlag, PlacementTool, Platform, Pointer, PointerButton, PointerPhase, PreviewModeAction, type ProjectCameraInfo, ProjectCameraManager, type ProjectVideoRenderer, QuadTreePosition, QuadraticInterpolant, QuadraticInterpolationMode, QuarticInterpolant, QuarticInterpolationMode, QuinticInterpolant, QuinticInterpolationMode, RecycleEntitiesAction, type RecycleEntityJson, RecycleManager, ReferenceApi, type ReferenceInfo, ReferencePoint, type ReferencePointParams, type ReferenceType, ReferencerManager, RemoveComponentAction, RemoveStateAction, RemoveVirtualChildAction, RenameComponentAction, RenameStateAction, type RequestOptions, ResourceManager, ResourceManagerSingleton, ResourcesAPI, type ResponseType, RoamingManager, type RuntimeComponent, RuntimeEngine, RuntimeScene, RuntimeSceneMode, type RuntimeSceneModeType, RuntimeSelectManager, SCENE_COMPONENT_TYPE, SRGB2Linear, SafeLoopArray, SceneCamera, type SceneJson, SceneManager, SceneObject, type SceneResourcesImage, type SceneResourcesImageConfig, type SceneResourcesMaterial, SelectAction, SelectManager, type SelectionMouseParams, SetComponentLockAction, SetComponentVisibleAction, SetCustomAttributeOfRootAction, SetDefaultStateAction, Signal, SinusoidalInterpolant, SinusoidalInterpolationMode, SortStateAction, SphereColliderObj, type StateJson, StaticRigidbodyComponent, StatsTool, SystemInfo, TEXTURE_SLOT_NAME, index as THREE, TangentMode, TextureLoader, type TextureSlotConfig, TextureUtils, TileDracoLoader, TransformAction, type TransformControlObject, type TransformControlObjectEventMap, TransformControls, type TransformPivotMode, TransformUtils, type TweenOption, type TweenUpdateFunction, TwinAnimationAction, TwinAnimationMixer, type TwinAnimationMixerEventTypeMap, type TwinAnimationMixerTimeUniType, TwinKeyframeTrack, type TwinKeyframeTrackOptions, type TwinKeyframeTrackValueType, TwinTransformControls, type UIComponentType, type UINode, UnitsUtils, UpdateCustomAttributeAction, UpdateDataAction, UpdateStateAction, type UploadMultiCheckType, UserAssetAPI, type ValidEventTypes, VirtualChildComponent, type VirtualChildComponentCtor, type VirtualChildData, VirtualRootComponent, type VirtualRootData, type WebPAnimationFrame, type WebPConfig, type WebPDecodedImageData, WebpUtils, WeightMode, XHRUtils, addEasyvEventListener, clamp, compareArrays, compareObject3d, compareVersion, convertObjToComponentJson, debounce, decryptGLB, deepClone, genUUID, getArraysAddPart, getArraysRemovePart, getDefaultEasyvEventListener, getFileNameAndExt, getFileNameFromUrl, getMD5, getMD5ByChunks, getSpaceId, getTextureImageType, getTypeVersionClassNameKey, getTypeVersionKey, imageToBlob, installProjectCameraManager, isAbsoluteUrl, isArray, isBase64Url, isEmptyObj, isEncryptedGLB, isInWeightEnabled, isNearlyZero, isNil, isNotWeighted, isNumber, isObject, isOutWeightEnabled, isPromise, isSameNumber, isString, lerp, makeFromColorTemperature, materialPreviewRenderer, materialThumbnailGenerator, meshMaterialSettings, minus, modalManager, objectToLocalPosition, objectToLocalQuaternion, quickSort, redirectToActive, redirectToInvited, redirectToLogin, removeEasyvEventListener, request, requestFile, resolveAbsoluteUrl, resolveRelativePath, setWasmUrl, sliceFile, sliceFileName, smoothDamp, smoothDampVec3, smoothStep, textureToJSON, toScaledVec2, toScaledVec3, transformIVec3ToVec3, union, uploadMaterialToUserAsset, uploadMulti, uploadMultiAbort };
8248
+ export { AbstractManager, AbstractSceneManager, AddStateAction, AddVirtualChildAction, AlignmentAXIS, AnimationCurve, AnimationCurveExtrapolation, type AnimationCurveJson, AnimationModeEnum, type AnimationModeType, type AnimationModeValueType, type ArgumentMap, AssetLibraryManager, type AssetTypeToContentMap, BackInterpolant, BackInterpolationMode, BingMapsProvider, Blackboard, BounceInterpolant, BounceInterpolationMode, BoundingBox, BoxColliderObj, CSSRenderer, Camera, type CameraInfo, type CameraMode, CancelablePromise, CanvasUtils, CapsuleColliderObj, Cesium3DTilesetComponent, CharacterColliderObj, CharacterControllerComponent, CircularInterpolant, CircularInterpolantMode, ColliderColors, ColliderObj, CollisionDetectionMode, type Color, type ColorType, type ColorValueMap, Component, type ComponentCategory, type ComponentCtor, type ComponentJson, ComponentManager, ComponentRef, type ComponentSettings, type ComponentUI, type ComponentUI_Custom, type ComponentUI_Effect, type ComponentUI_Function, type ComponentUI_Scene, type ComponentWithRb, CompositeAction, ConsoleLogger, type ControlledModeEditorProps, CreateComponentAction, type CreateComponentParams, type CreateCustomComponentParams, type CreateEntityDto, CreateModelComponentAction, CubicInterpolant, CubicInterpolationMode, CustomComponentApi, type CustomComponentContent, type CustomComponentContextMenuItem, type CustomComponentEditors, type CustomComponentListItem, CustomComponentManager, type CustomComponentModule, DEFAULT_CHUNK_SIZE, type DebounceOptions, DebugProvider, type DecodedWebPAnimationFrame, type DisableSelectType, DoubleMap, DragPoint, type DrawPointMapType, DrawPointName, DrawPointSprite, DynamicRigidbodyComponent, DynamicRigidbodyConstraints, EasyTwinTween, type EasyvFilterAttributeParam, type EasyvSwitchStateAnimationParam, type EasyvSwitchStateParam, type EasyvUpdateCustomAttributeParam, type EditMode, EditModeAction, type EditorActionInfo, EditorActionsManager, type EditorComp, type EditorContext, EditorHelper, EditorPanelManager, type EditorProps, ElasticInterpolant, ElasticInterpolationMode, EngineCSSRenderObject, type EngineConfiguration, EngineCubicBezierCurve3, type EngineEmitFunc, EntityAPI, EntityUtil, type EventArgs, EventEmitter, type EventListener, type EventName, type EventNames, ExponentialInterpolant, ExponentialInterpolantMode, FeatImageExt, FeatModelExt, FeatVideoExt, FileApi, type FileChunk, FileTypeEnum, FileUtil, Fsm, FsmState, GROUP_COMPONENT_TYPE, type GeoLocation, GeoTransformForCenterAndNorthMode, GeoTransformForReferencePoints, type GeoTransformOptions, GeographicModule, Geolocation, GeolocationUtils, GoogleMapsProvider, type GradientColorValue, HeightDebugProvider, HereMapsProvider, type HierarchyConfig, HtmlEvent, type ICanAccessEngine, ID_PREFIX_COMP_VIRTUAL_CHILD, type IEditorAction, type IHierarchyNode, type ILogger, type IManager, type IModelLoader, type ISerializable, type ITextureLoader, type IVector2, IVector3, type IVector4, type InitStateDto, InputManager, type InspectorGroupKey, InterpMode, type Keyframe, Keys, type LCCLoadConfig, type LCCObject, type LCCRender, type LODControl, LODFrustum, LODRadial, LODRaycast, Linear2SRGB, LoadSceneMode, LoadState, LogLevel, Logger, MODEL_COMPONENT_TYPE, MapBoxProvider, MapComponent, MapHeightNode, MapHeightNodeShader, MapNode, MapNodeGeometry, MapNodeHeightGeometry, MapPlaneNode, MapProvider, MapSphereNode, MapSphereNodeGeometry, MapTilerProvider, MapView, type MaterialConfig, type MaterialInfo, MaterialPreviewRenderer, type MaterialTextureProperties, MaterialThumbnailGenerator, type MaterialUVProperties, ModalManager, type ModelInfo, ModelLoader, type ModelLoaderResult, ModelUtil, type MultiTypeColor, type Nullable, type NumberState, OBBHelper, ObjectTransformAction, OpenMapTilesProvider, OpenStreetMapsProvider, type PartialSome, PhysicsCombineMode, PhysicsControllerCollisionFlag, PhysicsControllerNonWalkableModeEnum, PhysicsShapeFlag, PlacementTool, Platform, Pointer, PointerButton, PointerPhase, PreviewModeAction, type ProjectCameraInfo, ProjectCameraManager, type ProjectVideoRenderer, QuadTreePosition, QuadraticInterpolant, QuadraticInterpolationMode, QuarticInterpolant, QuarticInterpolationMode, QuinticInterpolant, QuinticInterpolationMode, RecycleEntitiesAction, type RecycleEntityJson, RecycleManager, ReferenceApi, type ReferenceInfo, ReferencePoint, type ReferencePointParams, type ReferenceType, ReferencerManager, RemoveComponentAction, RemoveStateAction, RemoveVirtualChildAction, RenameComponentAction, RenameStateAction, type RequestOptions, ResourceManager, ResourceManagerSingleton, ResourcesAPI, type ResponseType, RoamingManager, type RuntimeComponent, type EngineTickListener, registerEngineTickListener, unregisterEngineTickListener, RuntimeEngine, RuntimeScene, RuntimeSceneMode, type RuntimeSceneModeType, RuntimeSelectManager, SCENE_COMPONENT_TYPE, SRGB2Linear, SafeLoopArray, SceneCamera, type SceneJson, SceneManager, SceneObject, type SceneResourcesImage, type SceneResourcesImageConfig, type SceneResourcesMaterial, SelectAction, SelectManager, type SelectionMouseParams, SetComponentLockAction, SetComponentVisibleAction, SetCustomAttributeOfRootAction, SetDefaultStateAction, Signal, SinusoidalInterpolant, SinusoidalInterpolationMode, SortStateAction, SphereColliderObj, type StateJson, StaticRigidbodyComponent, StatsTool, SystemInfo, TEXTURE_SLOT_NAME, index as THREE, TangentMode, TextureLoader, type TextureSlotConfig, TextureUtils, TileDracoLoader, TransformAction, type TransformControlObject, type TransformControlObjectEventMap, TransformControls, type TransformPivotMode, TransformUtils, type TweenOption, type TweenUpdateFunction, TwinAnimationAction, TwinAnimationMixer, type TwinAnimationMixerEventTypeMap, type TwinAnimationMixerTimeUniType, TwinKeyframeTrack, type TwinKeyframeTrackOptions, type TwinKeyframeTrackValueType, TwinTransformControls, type UIComponentType, type UINode, UnitsUtils, UpdateCustomAttributeAction, UpdateDataAction, UpdateStateAction, type UploadMultiCheckType, UserAssetAPI, type ValidEventTypes, VirtualChildComponent, type VirtualChildComponentCtor, type VirtualChildData, VirtualRootComponent, type VirtualRootData, type WebPAnimationFrame, type WebPConfig, type WebPDecodedImageData, WebpUtils, WeightMode, XHRUtils, addEasyvEventListener, clamp, compareArrays, compareObject3d, compareVersion, convertObjToComponentJson, debounce, decryptGLB, deepClone, genUUID, getArraysAddPart, getArraysRemovePart, getDefaultEasyvEventListener, getFileNameAndExt, getFileNameFromUrl, getMD5, getMD5ByChunks, getSpaceId, getTextureImageType, getTypeVersionClassNameKey, getTypeVersionKey, imageToBlob, installProjectCameraManager, isAbsoluteUrl, isArray, isBase64Url, isEmptyObj, isEncryptedGLB, isInWeightEnabled, isNearlyZero, isNil, isNotWeighted, isNumber, isObject, isOutWeightEnabled, isPromise, isSameNumber, isString, lerp, makeFromColorTemperature, materialPreviewRenderer, materialThumbnailGenerator, meshMaterialSettings, minus, modalManager, objectToLocalPosition, objectToLocalQuaternion, quickSort, redirectToActive, redirectToInvited, redirectToLogin, removeEasyvEventListener, request, requestFile, resolveAbsoluteUrl, resolveRelativePath, setWasmUrl, sliceFile, sliceFileName, smoothDamp, smoothDampVec3, smoothStep, textureToJSON, toScaledVec2, toScaledVec3, transformIVec3ToVec3, union, uploadMaterialToUserAsset, uploadMulti, uploadMultiAbort };
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@easytwin/devkit",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "EasyTwin DevKit 核心:lib(函数库)+ bin(easytwin 命令)双导出",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "files": [
8
8
  "dist",
9
9
  "skills",
10
- "scene.example.json"
10
+ "scene.example.json",
11
+ "!**/*.map"
11
12
  ],
12
13
  "exports": {
13
14
  ".": {
@@ -28,6 +29,7 @@
28
29
  "devDependencies": {
29
30
  "@types/node": "^22.10.2",
30
31
  "tsup": "^8.3.5",
32
+ "esbuild": "^0.24.2",
31
33
  "typescript": "^5.7.2",
32
34
  "vitest": "^2.1.8",
33
35
  "three": "0.183.0",
@@ -53,7 +55,7 @@
53
55
  "registry": "https://registry.npmjs.org/"
54
56
  },
55
57
  "scripts": {
56
- "build": "tsup && node scripts/copy-runtime-types.mjs",
58
+ "build": "tsup && node scripts/copy-runtime-types.mjs && node scripts/bundle-runtime.mjs",
57
59
  "test": "vitest run",
58
60
  "typecheck": "tsc --noEmit"
59
61
  }
@@ -15,17 +15,19 @@ description: 当用户要开始使用 EasyTwin DevKit、配置应用级凭证(Ap
15
15
  "appSecret": "必填",
16
16
  "env": "可选,prod=正式 / test=测试,缺省 prod",
17
17
  "baseUrl": "可选,缺省按 env 选官方域名",
18
- "ossUrl": "可选,缺省官方 OSS"
18
+ "ossUrl": "可选,缺省官方 OSS",
19
+ "scenes": "可选,由 easytwin scene list 写入的场景摘要,不含 JSON 本体"
19
20
  }
20
21
  ```
21
22
 
22
- - 环境变量 `EASYTWIN_APP_ID` / `EASYTWIN_APP_SECRET` / `EASYTWIN_BASE_URL` / `EASYTWIN_ENV` / `EASYTWIN_OSS_URL` 优先于文件(CI 与不落盘场景)
23
- - 官方 API:正式 `http://saas-twin.k8s.dtstack.cn/`、测试 `http://saas-twin-test.k8s.dtstack.cn/`;缺省按 env 选择,`EASYTWIN_BASE_URL` 始终优先。
23
+ - 环境变量 `EASYTWIN_APP_ID` / `EASYTWIN_APP_SECRET` / `EASYTWIN_BASE_URL` / `EASYTWIN_ENV` / `EASYTWIN_OSS_URL` 优先于文件(CI 与不落盘场景)。请求带 `x-app-id`(App ID)与 `x-app-secret`(App Secret),不走 OP 网关。
24
+ - 官方 API:正式 `http://saas-twin.k8s.dtstack.cn/`、测试 `http://172.16.125.3:10100/`;缺省按 env 选择,`EASYTWIN_BASE_URL` 始终优先。
24
25
  - 官方 OSS:`https://dt-easyv-test.oss-cn-hangzhou.aliyuncs.com/`,供 twin runtime 加载 webp wasm / draco / 组件脚本;`EASYTWIN_OSS_URL` 始终优先。
25
26
  - 该文件含密钥,**永不入库**:`init` 已负责 gitignore,不要把它提交进版本库。
26
- - **本地测试**:`appId``appSecret` 都填 `test` 时进入本地测试模式,scene/upload 走本地 mock、不发网络请求( easytwin-scene / easytwin-upload)。仅限本地联调,严禁用假凭据碰真实服务端。
27
+ - `scenes` `easytwin scene list`(或插件刷新场景树)写入,下次 list 会全量覆盖;`init` 重写配置时不会保留旧列表。
28
+ - **本地测试**:`appId` 与 `appSecret` 都填 `test` 时进入本地测试模式,scene/upload/pull 走本地 mock、不发网络请求(见 easytwin-scene / easytwin-upload)。仅限本地联调,严禁用假凭据碰真实服务端。
27
29
 
28
30
  ## 步骤
29
31
 
30
32
  1. 若项目还没有 `easytwin.config.json`,运行 `easytwin init` 并按提示输入。
31
- 2. 校验:`easytwin scene list` 能列出场景即凭据有效;报错则检查 appId / appSecret 或环境变量覆盖。
33
+ 2. 校验:`easytwin scene list` 能列出场景即凭据有效,并会把场景 id/名称写入 `easytwin.config.json.scenes`;报错则检查 appId / appSecret 或环境变量覆盖。
@@ -5,7 +5,7 @@ description: 当用户要理解 EasyTwin 引擎内核(类层级、RuntimeEngine
5
5
 
6
6
  # 引擎内核(easytwin-runtime core)
7
7
 
8
- 对应 npm 包 `@easytwin/runtime` 的 `src/core/` 目录:引擎本体、场景、组件基类与基础设施。写渲染功能的主流程见 `easytwin-render`;本技能是引擎核心的完整 API 参考。
8
+ 对应 `@easytwin/runtime` 的 `src/core/` 目录:引擎本体、场景、组件基类与基础设施。第三方应用入口是 TwinApp 子类,主流程见 `easytwin-render`;本技能是引擎内部 API 参考。
9
9
 
10
10
  ## 核心关系速览
11
11
 
@@ -22,4 +22,4 @@ description: 当用户要理解 EasyTwin 引擎内核(类层级、RuntimeEngine
22
22
  - 需要"相机体系(Camera/SceneCamera/CameraControls/focus)"时读 `references/camera.md`
23
23
  - 需要"物理体系(PhysicsManager/PhysicsScene/物理开关)"时读 `references/physics.md`
24
24
 
25
- 组件生命周期钩子、状态/数据 API 与序列化结构分别在 `easytwin-render` 的 `references/lifecycle-events.md` 与 `references/scene-and-assets.md`,本技能不重复(虚拟子要素的序列化结构见本技能 `references/virtual-components.md`)。
25
+ 组件生命周期钩子、状态/数据 API 与序列化结构分别在 `easytwin-render` 的 `references/lifecycle-events.md` 与 `references/scene-and-assets.md`,本技能不重复(虚拟子要素的序列化结构见本技能 `references/virtual-components.md`)。
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## 概览
4
4
 
5
- 一个 `RuntimeEngine` 对应一个 DOM 容器(`engine.container`):
5
+ TwinApp `ctx.engine` 取用本对象。一个 `RuntimeEngine` 对应一个 DOM 容器(`engine.container`):
6
6
 
7
7
  - 注册并初始化五个 manager:`ResourceManager` / `SceneManager` / `CustomComponentManager` / `EditorActionsManager` / `PhysicsManager`;
8
8
  - 启动 `requestAnimationFrame` 渲染循环,每帧 `Time.update()` → `SceneManager.updateScene(deltaTime)`;
@@ -10,7 +10,7 @@
10
10
 
11
11
  ## create 与 EngineConfiguration
12
12
 
13
- 唯一入口 `RuntimeEngine.create(config)`(静态、异步):
13
+ 宿主创建入口 `RuntimeEngine.create(config)`(静态、异步)。TwinApp 用 `ctx.engine`,不必再调:
14
14
 
15
15
  ```ts
16
16
  const engine = await RuntimeEngine.create({
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: easytwin-develop
3
- description: 当用户开始 EasyTwin 第三方应用开发、需要了解整体开发工作流(配置凭证→拉场景→写渲染→上传)、或询问"接下来该做什么/从哪开始"时使用。其余 EasyTwin 技能的总纲。
3
+ description: 当用户开始 EasyTwin 第三方应用开发、需要了解整体开发工作流(配置凭证→拉工作区代码→拉场景→写 TwinApp 子类→预览测试→上传)、或询问"接下来该做什么/从哪开始"时使用。其余 EasyTwin 技能的总纲。
4
4
  ---
5
5
 
6
6
  # EasyTwin 开发工作流
@@ -8,9 +8,11 @@ description: 当用户开始 EasyTwin 第三方应用开发、需要了解整体
8
8
  EasyTwin DevKit 是 EasyTwin 第三方应用开发工具集。典型工作流:
9
9
 
10
10
  1. **配置凭证**:运行 `easytwin init` 生成项目级 `easytwin.config.json`(App ID / App Secret)。详见 `easytwin-bootstrap`。
11
- 2. **拉取场景**:`easytwin scene list` 列出场景,`easytwin scene pull <id>` 拉取场景 JSON 到本地,作为开发参考与预览输入。详见 `easytwin-scene`。
12
- 3. **编写渲染功能**:在工作区 `src/main.ts` `export default async function main(ctx)`(ctx = `{ engine, runtime, sceneJson }`),类型由 `easytwin skills sync` 分发,**不要** `npm install @easytwin/runtime`(公网不存在)。编译用 `easytwin bundle`,运行用插件预览页底部 Run。引擎内核见 `easytwin-core`。详见 `easytwin-render`(主力技能)。
13
- 4. **上传产物**:`easytwin upload <dir>` 全量覆盖上传到服务端,不可逆。详见 `easytwin-upload`。
11
+ 2. **拉取工作区代码**:`easytwin pull` 从服务端下载代码;远端为空则写入默认 TwinApp `src/main.ts`;本地已有文件时先 diff,默认只补缺失。详见 `easytwin-upload`。
12
+ 3. **拉取场景**:`easytwin scene list` 列出场景,`easytwin scene pull <id>` 拉取场景 JSON 到本地,作为开发参考与预览输入。详见 `easytwin-scene`。
13
+ 4. **编写渲染功能**:在工作区 `src/main.ts` 写 TwinApp 子类(`import { TwinApp } from "@easytwin/apps"`,`export default class App extends TwinApp { init; onSceneLoaded; onUpdate; ... }`)。类型由 `easytwin skills sync` 分发。编译用 `easytwin bundle`,运行用 `easytwin preview`(浏览器打开打印的 URL,点 Run)或插件预览页底部 Run。可上传子集只用 runtime 五件套导出;整包 API 仅本地预览。引擎内核见 `easytwin-core`。详见 `easytwin-render`(主力技能)。
14
+ 5. **预览测试**:在 `*.spec.ts` 里导出函数,`easytwin preview` 或插件预览页为每个导出生成按钮或输入框。测试文件不同步到服务端。详见 `easytwin-test`。
15
+ 6. **上传产物**:`easytwin upload` 对照远端区分新增/更新/删除,使服务端与本地工作区一致(跳过插件产物与 `*.spec.ts`,不可逆)。详见 `easytwin-upload`。
14
16
 
15
17
  ## 何时读哪个技能
16
18
 
@@ -19,11 +21,12 @@ EasyTwin DevKit 是 EasyTwin 第三方应用开发工具集。典型工作流:
19
21
  | 初始化 / 校验凭证 | easytwin-bootstrap |
20
22
  | 列场景、拉场景 JSON | easytwin-scene |
21
23
  | 用 twin runtime 写渲染 | easytwin-render |
24
+ | 给预览加可点击测试 / 写 `.spec.ts` | easytwin-test |
22
25
  | 理解引擎内核 / 基类 / 相机 / 物理 | easytwin-core |
23
- | 上传开发产物 | easytwin-upload |
26
+ | 上传 / 拉取工作区代码 | easytwin-upload |
24
27
 
25
28
  > 场景 JSON 格式以 easytwin-runtime 的 `SceneJson` 为准,详见 easytwin-scene。
26
29
 
27
30
  ## 本地测试
28
31
 
29
- 没有凭据或不想动服务端时,把 `appId` / `appSecret` 都设为 `test` 即进入本地测试模式:`scene list` / `scene pull` 读 devkit 包内的 `scene.example.json`,`upload` 只做本地空跑,这两条不发服务端请求。插件里的场景预览仍是三维场景页(打包的 twin runtime + 本地示例 JSON),系统库(draco/basis/webp)与组件脚本按官方 OSS(=ossUrl)在线加载。预览页 Run 在 mock 下同样可用。
32
+ 没有凭据或不想动服务端时,把 `appId` / `appSecret` 都设为 `test` 即进入本地测试模式:`scene list` / `scene pull` 读 devkit 包内的 `scene.example.json`,`upload` 只做本地空跑,`pull` 按远端为空写入默认 `src/main.ts`(已有则不覆盖),这三条不发服务端请求。`easytwin preview` 与插件预览仍是三维场景页(打包的 twin runtime + 本地示例 JSON),系统库(draco/basis/webp)与组件脚本按官方 OSS(=ossUrl)在线加载。预览页 Run 在 mock 下同样可用。
@@ -1,35 +1,74 @@
1
1
  ---
2
2
  name: easytwin-render
3
- description: 当用户要用 EasyTwin twin runtime 编写渲染功能(写 src/main.ts、预览页 Run、easytwin bundle、加载场景、开发自定义组件、调用渲染 API)时使用。这是 EasyTwin 渲染开发的唯一入口技能。
3
+ description: 当用户要用 EasyTwin twin runtime 编写渲染功能(写 src/main.ts TwinApp 子类、class extends TwinApp、easytwin preview、预览页 Run、easytwin bundle、加载场景、开发自定义组件、调用渲染 API)时使用。这是 EasyTwin 渲染开发的唯一入口技能。
4
4
  ---
5
5
 
6
6
  # 用 twin runtime 开发渲染功能
7
7
 
8
- `@easytwin/runtime` 是商业包,公网 npm 不存在,**严禁** `npm install @easytwin/runtime`。类型声明由 `easytwin skills sync` 写入项目 `.easytwin/types/`;运行走预览页底部 **Run** 按钮,或 `easytwin bundle` 做编译校验。
8
+ `@easytwin/runtime` 是商业包,公网 npm 不存在,类型由 `easytwin skills sync` 写入 `.easytwin/types/`。`TwinApp` 从 `@easytwin/apps` 引入(同样由 sync 分发)。运行走 `easytwin preview` 打开的预览页底部 **Run**,或插件预览,或 `easytwin bundle` 做编译校验。
9
9
 
10
- ## 编写与运行 main.ts
10
+ ## 编写 TwinApp 子类(可上传子集)
11
11
 
12
- 工作区固定入口 `src/main.ts`(缺失则编译报错)。只能依赖 `@easytwin/runtime`(相对路径的本地 TS 可以),禁止任何其他裸模块。
12
+ 工作区固定入口 `src/main.ts`。依赖只允许 `@easytwin/runtime` 与 `@easytwin/apps`(相对路径本地 TS 可以)。`export default` 必须是 `TwinApp` 子类:
13
13
 
14
14
  ```ts
15
- import type { EasyTwinRunContext } from "@easytwin/runtime";
16
-
17
- export default async function main(ctx: EasyTwinRunContext) {
18
- const { engine, runtime, sceneJson } = ctx;
19
- // 在已加载的场景上写渲染/交互逻辑
20
- void engine;
21
- void runtime;
22
- void sceneJson;
15
+ import { THREE } from "@easytwin/runtime";
16
+ import { TwinApp, type TwinAppContext } from "@easytwin/apps";
17
+
18
+ export default class App extends TwinApp {
19
+ async init(ctx: TwinAppContext) {
20
+ // engine / container 已有;scene / camera / runtimeScene 为 null
21
+ void ctx;
22
+ }
23
+
24
+ async onSceneLoaded(ctx: TwinAppContext) {
25
+ const mesh = new THREE.Mesh(
26
+ new THREE.BoxGeometry(1, 1, 1),
27
+ new THREE.MeshBasicMaterial({ color: 0x44aa88 }),
28
+ );
29
+ ctx.scene?.add(mesh);
30
+ ctx.sceneCleanup(() => {
31
+ ctx.scene?.remove(mesh);
32
+ });
33
+ }
34
+
35
+ onUpdate(ctx: TwinAppContext, delta: number, elapsed: number) {
36
+ void ctx;
37
+ void delta;
38
+ void elapsed;
39
+ }
40
+
41
+ onBeforeSceneUnload(ctx: TwinAppContext) {
42
+ void ctx;
43
+ }
44
+
45
+ onDispose(ctx: TwinAppContext) {
46
+ void ctx;
47
+ }
23
48
  }
24
49
  ```
25
50
 
26
- 1. 若还没有类型:运行 `easytwin skills sync`( tsconfig 会生成最小配置;已有 tsconfig 时在输出里看 `paths` 片段,自行加上 `"@easytwin/runtime": [".easytwin/types"]` 并建议 `skipLibCheck: true`)
27
- 2. 编译校验:`easytwin bundle`(缺省写出 `dist/main.js`,ESM + inline sourcemap)。检测到 lodash 等外部依赖会给出人话报错,不要据此去 npm install。
28
- 3. 运行:打开插件场景预览,点底部 **Run**。宿主内存编译(不落盘)→ blob URL + import map 把 `@easytwin/runtime` 指到页面已加载的同一 runtime 实例 → 先重新 `loadScene` 再调用 `export default main(ctx)`。编译失败不打断已渲染场景;mock 下同样可用。
51
+ 等价对象写法:`export default defineApp({ init, onSceneLoaded, onUpdate, ... })`。宿主只认这两种;函数导出(旧 `main`)会报错。
52
+
53
+ 可上传到在线 TwinApp runtime 导出名只有:`THREE`、`RuntimeEngine`、`SceneManager`、`LoadSceneMode`、`convertObjToComponentJson`。超出这些名字本地能编过并 warning,在线会失败。
54
+
55
+ 生命周期由宿主驱动。引擎与场景已在预览页创建;`init` 里场景字段为 null,物体与事件写在 `onSceneLoaded`,用 `ctx.sceneCleanup` 对称拆除。
56
+
57
+ | 钩子 | 时机 |
58
+ | --- | --- |
59
+ | `init` | 引擎 / 容器已有;场景字段为 null |
60
+ | `onSceneLoaded` | 宿主 `loadScene` 之后 |
61
+ | `onUpdate` | 引擎时钟每帧(加载中不调);仅此钩子 throw 走 `onError`(返回 `true` 继续) |
62
+ | `onBeforeSceneUnload` | 再 Run / 卸场景前 |
63
+ | `onDispose` | 应用拆除;引擎不 destroy,下次 Run 复用 |
64
+
65
+ 本地预览只有当前这一份场景,`ctx.sceneManager.loadScene` 会 reject。`ctx.assets.text/json` 读工作区相对路径。从 `ctx.engine` 取引擎,不要再 `RuntimeEngine.create`。
29
66
 
30
- `ctx`:`engine` 是现成 `RuntimeEngine`;`runtime` 是整个模块命名空间(枚举/类从此取);`sceneJson` 是当前场景数据。
67
+ 1. 若还没有类型:运行 `easytwin skills sync`(无 tsconfig 会生成最小配置,含 `@easytwin/runtime` 与 `@easytwin/apps` 的 paths;已有 tsconfig 时按输出片段自行添加)。
68
+ 2. 编译校验:`easytwin bundle`。lodash 等外部依赖会报错。超出在线 stub 的 runtime import 只 warning。
69
+ 3. 运行:`easytwin preview`(缺省用配置里的场景;也可 `easytwin preview <id>`),用浏览器打开打印的 URL,点底部 **Run**。有 EasyTwin 插件时也可打开场景预览再点 Run。再点 Run 会先 `onBeforeSceneUnload` / `onDispose`,复用同一台引擎。编译失败不打断已渲染场景;mock 下同样可用。给当前场景加可点击验证时写 `*.spec.ts`,见 `easytwin-test`。
31
70
 
32
- 完整「自己 create engine」的 API 细节见下方 references;预览页 Run 走注入式 ctx,不必在 main.ts 里再 `RuntimeEngine.create`。
71
+ `Component` / `VirtualRootComponent` 等整包 API 本地预览可用,但**不是**可上传子集;需要组件生命周期细节时读 `references/lifecycle-events.md`。
33
72
 
34
73
  ## 参考(references/)
35
74
 
@@ -1,13 +1,17 @@
1
1
  # 引入与初始化
2
2
 
3
+ ## TwinApp 里如何拿到引擎
4
+
5
+ 用户代码入口是 `src/main.ts` 的 `export default class App extends TwinApp`。预览页 / 在线环境已经创建引擎并加载场景;钩子里用 `ctx.engine` / `ctx.container` / `ctx.scene`。可上传子集只用 `THREE` / `RuntimeEngine` / `SceneManager` / `LoadSceneMode` / `convertObjToComponentJson`。
6
+
3
7
  ## 包信息
4
8
 
5
- - npm 包名:`@easytwin/runtime`(商业包,公网不存在)。**不要** `npm install`;类型由 `easytwin skills sync` 写入 `.easytwin/types/`,运行走预览页 Run 或 `easytwin bundle`。
6
- - 用户代码入口:`src/main.ts` `export default async function main(ctx)`,ctx 由预览页注入,一般不必自己 `RuntimeEngine.create`。
9
+ - npm 包名:`@easytwin/runtime`(商业包,公网不存在)。类型由 `easytwin skills sync` 写入 `.easytwin/types/`,运行走预览页 Run 或 `easytwin bundle`。
10
+ - `TwinApp` / `defineApp` / `TwinAppContext` `@easytwin/apps` 引入(同样由 sync 分发)。
7
11
 
8
- ## 初始化 RuntimeEngine
12
+ ## RuntimeEngine.create(宿主调用)
9
13
 
10
- 唯一入口:`RuntimeEngine.create(config)`(静态、异步)。
14
+ 工厂方法:`RuntimeEngine.create(config)`(静态、异步)。TwinApp 从 `ctx.engine` 取用已创建的实例。
11
15
 
12
16
  ```ts
13
17
  import { RuntimeEngine, SceneManager, LoadSceneMode } from "@easytwin/runtime";
@@ -1,6 +1,6 @@
1
1
  # 场景加载与资产
2
2
 
3
- > 说明:本节讲的是 runtime 的场景 JSON(组件树序列化结构,`SceneJson`,定义见 `src/core/interface.ts`)与资产加载。`easytwin scene pull` 拉取的服务端场景 JSON 同样以该结构为准(见 easytwin-scene)。可用 `SceneManager.importScene` `loadScene` 把本地 JSON 喂给 runtime
3
+ > 说明:本节讲的是 runtime 的场景 JSON(组件树序列化结构,`SceneJson`,定义见 `src/core/interface.ts`)与资产加载。`easytwin scene pull` 拉取的服务端场景 JSON 同样以该结构为准(见 easytwin-scene)。TwinApp 场景由宿主加载;本地预览里 `ctx.sceneManager.loadScene` reject。下面是 SceneManager 内部 API
4
4
 
5
5
  ## 场景管理(SceneManager)
6
6
 
@@ -1,54 +1,57 @@
1
- ---
2
- name: easytwin-scene
3
- description: 当用户要列出场景、查看有哪些场景、或把某个场景的 JSON 拉到本地作为开发参考/预览输入时使用。
4
- ---
5
-
6
- # 场景管理
7
-
8
- - `easytwin scene list`:列出凭据可见的场景。
9
- - `easytwin scene pull <id> [--out <path>]`:拉取场景 JSON 到本地,缺省输出 `./<id>.scene.json`。
10
-
11
- ## 场景 JSON 格式
12
-
13
- 场景 JSON 以 easytwin-runtime 的 `SceneJson` 为准(`packages/easytwin-runtime/src/core/interface.ts`),即组件树序列化结构:
14
-
15
- ```ts
16
- type StateJson<T = any> = { id: string; name: string; config: T; using: boolean; rank: number };
17
-
18
- type ComponentJson<S = any, D = any> = {
19
- id: string; // 实体 id,仅用于层级关系
20
- active: boolean; // 世界大纲 config 修改
21
- lock: boolean; // 仅编辑器生效(是否被选中)
22
- collapsed: boolean; // 世界大纲 config 修改
23
- componentId: string; // 组件 id,兼容后端绑定关系
24
- name: string;
25
- type: string;
26
- version: string;
27
- states?: StateJson<S>[];
28
- data?: D;
29
- children: ComponentJson[];
30
- parentId: string | null; // 引擎不直接存储 parentId
31
- };
32
-
33
- interface SceneJson { id: string; name: string; sceneComponent: ComponentJson; }
34
- ```
35
-
36
- `easytwin scene pull` 按服务端原样保存;该结构可直接作为渲染开发参考与本地预览输入(runtime 的 `SceneManager.loadScene` / `importScene` 接受它,详见 easytwin-render 的 references/scene-and-assets.md)。
37
-
38
- ## 本地测试模式(mock)
39
-
40
- 当 `appId` 与 `appSecret` 均为 `test` 时,`scene list` / `scene pull` 不再请求服务端,改读 devkit 包内 `scene.example.json`:
41
-
42
- - 场景 id 取 `objs[].sceneId` 首个非空值(当前示例为 `sceJTHH9yoqFyRyS9`),场景名固定为「本地示例场景」;
43
- - `scene pull` 的 id 必须与示例 id 一致,否则报错;
44
- - 命令输出会标注「本地测试模式」。该模式仅用于本地联调,不发网络请求。
45
-
46
- ## 典型用法
47
-
48
- 拉取参考场景,作为渲染开发与本地预览的输入:
49
-
50
- ```bash
51
- easytwin scene list
52
- easytwin scene pull scene-123 --out ./scenes/scene-123.json
53
- ```
54
-
1
+ ---
2
+ name: easytwin-scene
3
+ description: 当用户要列出场景、查看有哪些场景、或把某个场景的 JSON 拉到本地作为开发参考/预览输入时使用。
4
+ ---
5
+
6
+ # 场景管理
7
+
8
+ - `easytwin scene list`:列出 SDK 应用已关联的场景(id 为 Scene Key),并把摘要(id / name / linkedSceneId / snapshotUrl / defaultLoading)写入项目 `easytwin.config.json` 的 `scenes` 数组(全量覆盖,不含场景 JSON)。
9
+ - `easytwin scene pull <id> [--out <path>]`:按 Scene Key(或关联记录 id)拉取场景快照 JSON 到本地,缺省输出 `./<id>.scene.json`。
10
+
11
+ ## 场景 JSON 格式
12
+
13
+ 场景 JSON 以 easytwin-runtime 的 `SceneJson` 为准(`packages/easytwin-runtime/src/core/interface.ts`),即组件树序列化结构:
14
+
15
+ ```ts
16
+ type StateJson<T = any> = { id: string; name: string; config: T; using: boolean; rank: number };
17
+
18
+ type ComponentJson<S = any, D = any> = {
19
+ id: string; // 实体 id,仅用于层级关系
20
+ active: boolean; // 世界大纲 config 修改
21
+ lock: boolean; // 仅编辑器生效(是否被选中)
22
+ collapsed: boolean; // 世界大纲 config 修改
23
+ componentId: string; // 组件 id,兼容后端绑定关系
24
+ name: string;
25
+ type: string;
26
+ version: string;
27
+ states?: StateJson<S>[];
28
+ data?: D;
29
+ children: ComponentJson[];
30
+ parentId: string | null; // 引擎不直接存储 parentId
31
+ };
32
+
33
+ interface SceneJson { id: string; name: string; sceneComponent: ComponentJson; }
34
+ ```
35
+
36
+ `easytwin scene pull` 按服务端原样保存;该结构可直接作为渲染开发参考与本地预览输入(runtime 的 `SceneManager.loadScene` / `importScene` 接受它,详见 easytwin-render 的 references/scene-and-assets.md)。
37
+
38
+ ## 本地测试模式(mock)
39
+
40
+ 当 `appId` 与 `appSecret` 均为 `test` 时,`scene list` / `scene pull` 不再请求服务端,改读 devkit 包内 `scene.example.json`:
41
+
42
+ - 场景 id 取 `objs[].sceneId` 首个非空值(当前示例为 `sceJTHH9yoqFyRyS9`),场景名固定为「本地示例场景」;
43
+ - `scene pull` 的 id 必须与示例 id 一致,否则报错;
44
+ - 命令输出会标注「本地测试模式」。该模式仅用于本地联调,不发网络请求。
45
+
46
+ ## 典型用法
47
+
48
+ 拉取参考场景,作为渲染开发与本地预览的输入:
49
+
50
+ ```bash
51
+ easytwin scene list
52
+ easytwin preview
53
+ easytwin scene pull scene-123 --out ./scenes/scene-123.json
54
+ ```
55
+
56
+ `easytwin preview [sceneId]` 起本地预览页(三维 + Run + 测试控件),用浏览器打开打印的 URL。缺省 sceneId 取配置 `scenes` 里 `defaultLoading` 否则首项。
57
+
@@ -0,0 +1,47 @@
1
+ ---
2
+ name: easytwin-test
3
+ description: 当用户要写预览测试、工作区 .spec.ts、给场景预览加测试按钮或输入框、或确认测试文件会不会被上传时使用。
4
+ ---
5
+
6
+ # 预览测试:`*.spec.ts`
7
+
8
+ 工作区任意目录的 `*.spec.ts`(建议 `src/*.spec.ts`)只给**本地场景预览**用。`easytwin preview` 或插件打开预览时扫描命名导出的函数,每个导出一个控件;点击后用当前 `TwinAppContext` 调用。这些文件留在本地,`easytwin upload` / `pull` 都跳过。
9
+
10
+ ## 导出约定
11
+
12
+ - 只认 **named export 的函数**( `export function` / `export async function` / `export const name = …` )。不认 `export default`、class、type、再导出。
13
+ - 第一个参数是 `TwinAppContext`(与 TwinApp 钩子同一份 ctx:引擎、场景、camera、`assets`、`logger`、`cleanup` / `sceneCleanup`)。
14
+ - **只有 ctx**:预览显示按钮,文案=函数名。
15
+ - **ctx 后再跟参数**:预览显示输入框+执行,把输入框字符串当作第二个参数传入。
16
+
17
+ ```ts
18
+ import type { TwinAppContext } from "@easytwin/apps";
19
+ import { THREE } from "@easytwin/runtime";
20
+
21
+ export async function addBox(ctx: TwinAppContext) {
22
+ const mesh = new THREE.Mesh(
23
+ new THREE.BoxGeometry(1, 1, 1),
24
+ new THREE.MeshBasicMaterial({ color: 0xff6644 }),
25
+ );
26
+ ctx.scene?.add(mesh);
27
+ ctx.sceneCleanup(() => {
28
+ ctx.scene?.remove(mesh);
29
+ });
30
+ }
31
+
32
+ export async function logName(ctx: TwinAppContext, name: string) {
33
+ ctx.logger.info("test", name);
34
+ }
35
+ ```
36
+
37
+ 依赖白名单与 TwinApp 相同:只允许 `@easytwin/runtime`、`@easytwin/apps` 和相对路径。通过 `ctx` 操作**当前预览已加载的场景**;不要 `RuntimeEngine.create`,不要 `import` `src/main.ts`(会打进另一份应用,不是正在跑的那份)。加到场景里的物体用 `ctx.sceneCleanup` 对称拆除。
38
+
39
+ 可上传的 runtime 导出名仍是五件套;超出的名字本地预览能跑,上传在线 TwinApp 可能编不过(测试文件本身不会被上传)。
40
+
41
+ ## 怎么跑
42
+
43
+ 1. 把 spec 写到工作区(文件名以 `.spec.ts` 结尾)。
44
+ 2. 运行 `easytwin preview`(或打开插件场景预览):场景加载后,Run 栏上方出现测试控件;点 **刷新测试** 可重扫而不关预览。
45
+ 3. 点按钮或填输入框再执行。不必先点 Run;若已 Run,测试与 TwinApp 共用同一台引擎。
46
+
47
+ 完成标准:预览里能看到每个导出对应的控件,点下去函数被调用,且 `easytwin upload` 的文件列表里没有该 `.spec.ts`。
@@ -1,25 +1,39 @@
1
- ---
2
- name: easytwin-upload
3
- description: 当用户要把本地开发产物目录上传回 EasyTwin、全量覆盖服务端内容、或询问上传是否可逆/会覆盖什么时使用。
4
- ---
5
-
6
- # 全量上传(覆盖不可逆)
7
-
8
- `easytwin upload <dir>` 把 `<dir>` 下的全部文件上传,按 App ID 决定的目标空间**全量覆盖**。
9
-
10
- > ⚠️ **覆盖不可逆**:上传会覆盖服务端同名内容,没有本地清单与回滚机制。上传前务必确认目录内容与目标空间。
11
-
12
- ## 行为
13
-
14
- - 递归收集 `<dir>` 下所有文件(默认跳过 `.git`)。
15
- - 逐文件 multipart 上传,带进度输出。
16
- - 上传目标空间由凭据(App ID)决定;pull 场景与 upload 目录是两条独立能力,互不引用。
17
-
18
- ## 本地测试模式(mock)
19
-
20
- `appId` `appSecret` 均为 `test` 时,`easytwin upload <dir>` 退化为本地空跑(dry-run):只收集与统计文件、不上传,进度照常上报,输出标注「本地测试模式」。适合在无凭据/不想动服务端时演练上传流程。
21
-
22
- ## 步骤
23
-
24
- 1. 确认目标空间(App ID)与目录内容。
25
- 2. `easytwin upload <dir>`,观察进度与完成摘要。
1
+ ---
2
+ name: easytwin-upload
3
+ description: 当用户要把本地工作区上传回 EasyTwin、从服务端拉取工作区代码、远端没有代码时创建默认文件、或询问上传是否可逆/与本地 diff 如何同步时使用。
4
+ ---
5
+
6
+ # 工作区代码:拉取与全量上传
7
+
8
+ 上传与拉取共用同一套工作区代码接口,方向相反。
9
+
10
+ ## 拉取:`easytwin pull [dir]`
11
+
12
+ 从服务端下载 App ID 对应的工作区文件到 `[dir]`(缺省当前目录)。
13
+
14
+ - 远端为空:本地没有 `src/main.ts` 时写入默认 TwinApp 子类入口;本地已有入口则不覆盖。
15
+ - 远端有文件:与本地做 diff。`identical` 跳过,`remote-only` 写入,`local-only` 保留,**内容冲突默认不覆盖**。
16
+ - `--force` 才用远端内容覆盖冲突文件;即使 `--force` 也不删除仅本地文件。
17
+ - `--dry-run` 只打印 diff,不写盘。
18
+ - 本地测试模式(`appId`/`appSecret` 均为 `test`):不发请求,按远端为空处理。
19
+
20
+ 有冲突时先看摘要,确认要用远端覆盖再加 `--force`。插件里可对冲突文件打开「远程 本地」diff。
21
+
22
+ ## 上传:`easytwin upload [dir]`
23
+
24
+ 把工作区(缺省当前目录)上传,使服务端与本地一致(全量对齐,不可逆)。**不选目录**:插件按钮与缺省 CLI 都以项目根为准。
25
+
26
+ > ⚠️ **覆盖不可逆**:远端多余文件会删除,同名内容会更新,没有本地清单与回滚机制。
27
+
28
+ - 递归收集目录下文件,默认只处理 `.ts` / `.tsx` / `.js` / `.json`;并跳过插件产物与相关路径:`.git` / `node_modules` / `dist` / `.easytwin` / `.cursor` / `.claude` / `.qoder` / `.vscode`、`easytwin.config.json`、`.gitignore`、`tsconfig.json` / `tsconfig.*.json`、`*.scene.json`、`*.spec.ts`(预览测试,见 easytwin-test)。
29
+ - 先 `POST .../share/sdk-application-code/pull` 拉远端文件,本地 diff 后一次 `POST .../share/sdk-application-code/push`(`create`/`update`/`delete`);内容相同跳过、无变更不发 push。不请求仍走 OP 网关的 `workspace-config`。
30
+ - 上传目标空间由凭据(`x-app-id` + `x-app-secret`)决定;场景 pull 与工作区 pull/upload 是独立能力,互不引用。
31
+ - 认证头 `x-app-id` = App ID、`x-app-secret` = App Secret,不走 OP 网关。
32
+
33
+ 当 `appId` 与 `appSecret` 均为 `test` 时,`easytwin upload` 退化为本地空跑(dry-run):只收集与统计文件、不上传,进度照常上报,输出标注「本地测试模式」。
34
+
35
+ ## 步骤
36
+
37
+ 1. 新项目或本地还没有代码:`easytwin pull`(远端空则得到默认 `src/main.ts`)。
38
+ 2. 本地已有改动且可能与远端不同:`easytwin pull --dry-run` 看 diff,再决定是否 `--force`。
39
+ 3. 确认目标空间(App ID)后,`easytwin upload` 上传工作区(不可逆;不含插件产物与 `*.spec.ts`)。