chore(P2): normalize line endings, add .editorconfig, run lint in CI, sync docs

This commit is contained in:
flash555588 2026-06-15 17:01:17 +08:00
parent 83251a78bd
commit 69ac33d719
20 changed files with 7114 additions and 7074 deletions

View file

@ -7,7 +7,7 @@ on:
workflow_dispatch:
inputs:
tag:
description: "Release tag to publish, for example 0.4.0"
description: "Release tag to publish, for example 0.5.5"
required: false
permissions:
@ -36,6 +36,9 @@ jobs:
- name: Typecheck
run: npm run typecheck
- name: Lint
run: npm run lint
- name: Verify knowledge index
run: npm run verify:knowledge-index

View file

@ -1,5 +1,26 @@
# Changelog
## Unreleased
- Security: sanitize remote draft output and model-derived metadata before writing generated notes.
- Security: validate converter command paths and reject shell metacharacters.
- Stability: flush pending plugin store state on unload and log previously swallowed folder-creation errors.
- Stability: handle WebGL context loss/restoration in Three.js, Babylon.js, and 3dgrid previews.
- Stability: add outer timeout to conversion manager to prevent hung converters from blocking previews.
- Performance: pause Babylon.js preview render loops when the canvas leaves the viewport.
- Performance: skip unchanged cells in Babylon.js 3dgrid rendering.
- Performance: cap annotation pins and batch DOM reads/writes in label avoidance.
- Testing: add Vitest with unit tests for escape-html, remote-draft sanitization, and conversion manager timeout/deduplication.
- Build: remove unused `@babylonjs/gui`, `@babylonjs/materials`, and `@babylonjs/serializers` dependencies.
## 0.5.5
- Align release version metadata.
## 0.5.3
- Address Obsidian review warnings.
## 0.5.1
- Add annotation bookmark display modes for full snippets, compact surfaces, and dots; keep bookmark popovers open while hovered and hide occluded bookmarks fully.

1454
README.md

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@ README, implementation, verification scripts, and release/security docs.
AI Model Workbench is an Obsidian plugin that renders 3D model files inside a vault,
adds 3D annotations/bookmarks, and generates linked knowledge notes from model evidence.
The current package version is `0.4.0`.
The current package version is `0.5.5`.
Important runtime files:
@ -216,11 +216,11 @@ npm run verify:preview -- --model "models/resource-fixtures/grouped-parts/groupe
2. Run `npm run build`.
3. Run `npm run verify:release`.
4. Scan for tokens as described in `SECURITY.md`.
5. Publish through GitHub Actions with a tag such as `0.4.0` (no `v` prefix).
5. Publish through GitHub Actions with a tag such as `0.5.5` (no `v` prefix).
## Current Follow-Up Direction
Short-term product direction after `0.4.0`:
Short-term product direction after `0.5.5`:
- Tighten auto part registration and cross-model part reuse feedback.
- Keep improving direct workbench UX without prematurely moving all workbench routes.

View file

@ -24,6 +24,18 @@ export default defineConfig([
parserOptions: { project: "./tsconfig.json" },
},
},
{
files: ["src/**/*.test.ts"],
languageOptions: {
globals: {
setTimeout: "readonly",
clearTimeout: "readonly",
},
},
rules: {
"obsidianmd/prefer-active-window-timers": "off",
},
},
{
files: ["scripts/**/*.{js,mjs,ts}", "*.config.mjs"],
languageOptions: {

848
main.js

File diff suppressed because one or more lines are too long

View file

@ -1,10 +1,10 @@
{
"id": "ai-model-workbench",
"name": "AI Model Workbench",
"version": "0.5.5",
"minAppVersion": "1.5.0",
"description": "Turn 3D models into linked knowledge assets.",
"author": "flash",
"authorUrl": "https://github.com/flash555588",
"isDesktopOnly": false
}
{
"id": "ai-model-workbench",
"name": "AI Model Workbench",
"version": "0.5.5",
"minAppVersion": "1.5.0",
"description": "Turn 3D models into linked knowledge assets.",
"author": "flash",
"authorUrl": "https://github.com/flash555588",
"isDesktopOnly": false
}

View file

@ -1,47 +1,49 @@
{
"name": "obsidian-ai-model-workbench",
"version": "0.5.5",
"private": true,
"description": "Obsidian plugin for turning 3D models into linked knowledge assets.",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "node esbuild.config.mjs production",
"typecheck": "tsc --noEmit --skipLibCheck",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"verify:preview": "node scripts/verify-preview.mjs",
"verify:preview:rollback": "node scripts/verify-preview.mjs --rollout babylon-safe",
"verify:preview:success": "node scripts/verify-preview-success.mjs",
"verify:obsidian": "node scripts/verify-obsidian.mjs",
"verify:release": "node scripts/verify-release-assets.mjs",
"install:vault": "node scripts/install-to-vault.mjs",
"verify:settings": "node scripts/verify-settings-migration.mjs",
"verify:remote-draft": "node scripts/verify-remote-draft.mjs",
"verify:knowledge-index": "node scripts/verify-knowledge-index.mjs",
"verify:diagnostics": "node scripts/verify-diagnostics.mjs"
},
"devDependencies": {
"@codemirror/language": "^6.12.3",
"@codemirror/state": "^6.5.0",
"@codemirror/view": "^6.38.6",
"@lezer/common": "^1.5.2",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10",
"@types/node": "^22.15.17",
"@types/three": "^0.184.1",
"@typescript-eslint/parser": "^8.59.2",
"@vitest/coverage-v8": "^4.1.9",
"esbuild": "^0.28.1",
"eslint": "^9.39.4",
"eslint-plugin-obsidianmd": "^0.2.9",
"obsidian": "^1.8.7",
"playwright-core": "^1.59.1",
"typescript": "^5.8.3",
"vitest": "^4.1.9"
},
"dependencies": {
"@babylonjs/core": "^9.6.0",
"@babylonjs/loaders": "^9.6.0",
"three": "^0.184.0"
}
}
{
"name": "obsidian-ai-model-workbench",
"version": "0.5.5",
"private": true,
"description": "Obsidian plugin for turning 3D models into linked knowledge assets.",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "node esbuild.config.mjs production",
"typecheck": "tsc --noEmit --skipLibCheck",
"lint": "eslint src scripts --max-warnings=0",
"lint:fix": "eslint src scripts --fix",
"test": "vitest run",
"test:coverage": "vitest run --coverage",
"verify:preview": "node scripts/verify-preview.mjs",
"verify:preview:rollback": "node scripts/verify-preview.mjs --rollout babylon-safe",
"verify:preview:success": "node scripts/verify-preview-success.mjs",
"verify:obsidian": "node scripts/verify-obsidian.mjs",
"verify:release": "node scripts/verify-release-assets.mjs",
"install:vault": "node scripts/install-to-vault.mjs",
"verify:settings": "node scripts/verify-settings-migration.mjs",
"verify:remote-draft": "node scripts/verify-remote-draft.mjs",
"verify:knowledge-index": "node scripts/verify-knowledge-index.mjs",
"verify:diagnostics": "node scripts/verify-diagnostics.mjs"
},
"devDependencies": {
"@codemirror/language": "^6.12.3",
"@codemirror/state": "^6.5.0",
"@codemirror/view": "^6.38.6",
"@lezer/common": "^1.5.2",
"@lezer/highlight": "^1.2.3",
"@lezer/lr": "^1.4.10",
"@types/node": "^22.15.17",
"@types/three": "^0.184.1",
"@typescript-eslint/parser": "^8.59.2",
"@vitest/coverage-v8": "^4.1.9",
"esbuild": "^0.28.1",
"eslint": "^9.39.4",
"eslint-plugin-obsidianmd": "^0.2.9",
"obsidian": "^1.8.7",
"playwright-core": "^1.59.1",
"typescript": "^5.8.3",
"vitest": "^4.1.9"
},
"dependencies": {
"@babylonjs/core": "^9.6.0",
"@babylonjs/loaders": "^9.6.0",
"three": "^0.184.0"
}
}

View file

@ -1,345 +1,345 @@
export const en = {
// Section headers
"settings.title": "AI 3d model workbench",
"settings.folders": "Folders",
"settings.behavior": "Behavior",
"settings.converters": "Converters",
"settings.converterMenu": "Model converters",
"settings.converterMenu.desc": "Closed by default. Open this section only when you want to manually enable an optional local conversion route.",
"settings.environmentInspector": "Environment inspector",
"settings.environmentInspector.desc": "Closed by default. Open this section when you need to configure command paths or run environment checks.",
"settings.paths": "Converter paths",
"settings.diagnostics": "Converter command diagnostics",
"settings.performance": "Performance & display",
"settings.mobileSupport": "Mobile support",
"settings.knowledgeGeneration": "Knowledge generation",
// Folders
"settings.sourceModelFolder": "Source model folder",
"settings.sourceModelFolder.desc": "Vault folder where source model files are stored.",
"settings.reportFolder": "Report folder",
"settings.reportFolder.desc": "Vault folder where generated knowledge notes are saved.",
"settings.partFolder": "Part notes folder",
"settings.partFolder.desc": "Vault folder where generated part note drafts are saved.",
"settings.snapshotFolder": "Snapshot folder",
"settings.snapshotFolder.desc": "Vault folder where exported snapshots are saved.",
// Behavior
"settings.autoGenerateKnowledgeNotes": "Auto-generate knowledge notes",
"settings.autoGenerateKnowledgeNotes.desc": "Reserved for a future automation flow. For now, generate notes manually from the command palette.",
"settings.annotationPreviewMode": "Annotation preview mode",
"settings.annotationPreviewMode.desc": "Choose how bound note previews render in annotation popovers and the editor.",
"settings.annotationPreviewMode.plainText": "Plain text",
"settings.annotationPreviewMode.markdown": "Markdown",
"settings.annotationDisplayMode": "Annotation display mode",
"settings.annotationDisplayMode.desc": "Choose how bookmark pins appear over the model.",
"settings.annotationDisplayMode.snippet": "Full snippet",
"settings.annotationDisplayMode.surface": "Single surface",
"settings.annotationDisplayMode.dot": "Single dot",
"settings.previewRendererRollout": "Preview compatibility mode",
"settings.previewRendererRollout.desc": "Controls how widely the Three.js preview path is used for single-model previews (GLB, GLTF, STL, PLY, OBJ). Switch back to Compatibility mode if pin projection, occlusion, edit pins, snapshots, or toolbar behavior regress. 3dgrid is not affected by this setting.",
"settings.previewRendererRollout.babylonSafe": "Compatibility mode",
"settings.previewRendererRollout.readonly": "Reading surfaces only",
"settings.previewRendererRollout.direct": "Reading + file view (Recommended)",
"settings.useThreeRenderer": "Use Three.js renderer",
"settings.useThreeRenderer.desc": "Toggle between Three.js (faster, lighter) and Babylon.js (full compatibility) for single-model previews. Three.js supports GLB/GLTF/STL/PLY/OBJ. 3dgrid always uses Babylon.js.",
"settings.experimentalThreeWorkbench": "Experimental Three workbench",
"settings.experimentalThreeWorkbench.desc": "Try the Three.js workbench path for direct GLB/GLTF files only. If loading fails, the file view falls back to Babylon.js automatically.",
"settings.autoRotateDefault": "Auto-rotate by default",
"settings.autoRotateDefault.desc": "Start model previews with auto-rotation enabled.",
"settings.snapshotNaming": "Snapshot naming",
"settings.snapshotNaming.desc": "How exported snapshot files are named.",
"settings.snapshotNaming.modelName": "Model name + timestamp",
"settings.snapshotNaming.timestamp": "Timestamp only",
"settings.logLevel": "Log level",
"settings.logLevel.desc": "Controls plugin runtime log verbosity in the developer console.",
"settings.language": "Language",
"settings.language.desc": "Display language for plugin settings. Takes effect immediately.",
"settings.analysisMode": "AI drafting mode",
"settings.analysisMode.desc": "Controls whether knowledge-note generation stays local or also requests a sanitized remote draft. Raw model upload is blocked by the current client.",
"settings.analysisMode.local": "Local evidence only",
"settings.analysisMode.hybrid": "Local evidence + remote draft",
"settings.analysisMode.remote": "Remote draft from evidence",
"settings.serviceBaseUrl": "Draft service URL",
"settings.serviceBaseUrl.desc": "Optional base URL for a service that accepts POST /draft-note. Leave empty to keep all drafting local.",
"settings.sendGeometrySummaryToRemote": "Send geometry summary",
"settings.sendGeometrySummaryToRemote.desc": "Allow sanitized mesh counts, bounds, part candidates, annotation coordinates, and nearest-part links to be included in remote draft input.",
"settings.sendPreviewImagesToRemote": "Send preview image references",
"settings.sendPreviewImagesToRemote.desc": "Allow generated preview image paths to be listed in the remote draft input. Image bytes are not uploaded by this client.",
"settings.sendRawModelToRemote": "Send raw model file",
"settings.sendRawModelToRemote.desc": "Reserved for future explicit upload support. If enabled manually, remote draft requests are blocked instead of uploading the model.",
// Converters
"settings.enableCad": "Enable cad conversion for step, iges, and brep files",
"settings.enableCad.desc": "Enable cad conversion for step, iges, and brep formats. Requires cadquery and trimesh in your python environment.",
"settings.enableObj2gltf": "Enable obj2gltf converter (experimental)",
"settings.enableObj2gltf.desc": "Keep obj direct loading as the default. Enable this only if you want an optional local normalization route through obj2gltf.",
"settings.preferObj2gltf": "Prefer obj2gltf for obj",
"settings.preferObj2gltf.desc": "Recommended default is off. Turn this on only when you want normalized output files or direct obj loading is not good enough.",
"settings.enableFbx2gltf": "Enable FBX2glTF converter",
"settings.enableFbx2gltf.desc": "Enable conversion for fbx files via FBX2glTF. Requires the FBX2glTF binary installed locally.",
"settings.enableMesh": "Enable mesh conversion for 3mf and dae files",
"settings.enableMesh.desc": "Enable conversion for 3mf and dae formats via python trimesh. Requires trimesh, numpy, networkx, and pycollada in your python environment.",
"settings.enableSldprt": "Enable sldprt conversion for SolidWorks files",
"settings.enableSldprt.desc": "Enable conversion for SolidWorks sldprt files via FreeCAD. Requires FreeCAD installed locally.",
"settings.mobileSupport.desc": "On iOS, iPadOS, and Android, direct formats like GLB, GLTF, STL, OBJ, and PLY are supported. Local converter settings and diagnostics remain desktop-only.",
// Converter paths
"settings.pythonCmd": "Path to the python command for cad conversion",
"settings.pythonCmd.desc": "Optional path to the python command used for cad conversion. Windows usually uses py. macOS and Linux usually use python3. Overrides auto-discovery when set.",
"settings.freecadCmd": "Path to the FreeCAD command for sldprt conversion",
"settings.freecadCmd.desc": "Optional path to the FreeCAD command used for SolidWorks file conversion. Windows usually uses FreeCADCmd.exe, macOS usually uses FreeCADCmd, and Linux usually uses freecadcmd. Overrides auto-discovery when set.",
"settings.obj2gltfCmd": "Path to the obj2gltf command",
"settings.obj2gltfCmd.desc": "Optional path to the obj2gltf command. Windows usually uses obj2gltf.cmd, and macOS and Linux usually use obj2gltf. Overrides auto-discovery when set.",
"settings.fbx2gltfCmd": "FBX2glTF command path",
"settings.fbx2gltfCmd.desc": "Optional path to the FBX2glTF command. Windows usually uses FBX2glTF.exe, and macOS and Linux usually use FBX2glTF. Overrides auto-discovery when set.",
"settings.assimpCmd": "Path to the python command for 3mf and dae conversion",
"settings.assimpCmd.desc": "Optional path to the python command used for 3mf and dae conversion. Windows usually uses py. macOS and Linux usually use python3. Overrides auto-discovery when set.",
// Diagnostics
"settings.diagnostics.desc": "Shows the exact executable path the plugin would use right now and runs lightweight self-checks for Python environments and converter CLIs.",
"settings.diagnostics.idle": "Diagnostics are off by default. Click Check now to run them manually.",
"settings.diagnostics.checkNow": "Check now",
"settings.diagnostics.checking": "Checking...",
"settings.diagnostics.refreshed": "Converter command diagnostics refreshed.",
"settings.diagnostics.checkingAvailability": "Checking converter command availability...",
"settings.diagnostics.available": "available",
"settings.diagnostics.notFound": "not found",
"settings.diagnostics.sourceLabel": "Source",
"settings.diagnostics.commandLabel": "Command",
"settings.diagnostics.resolvedPathLabel": "Resolved path",
"settings.diagnostics.selfCheckLabel": "Self-check",
"settings.diagnostics.selfCheckOk": "passed",
"settings.diagnostics.selfCheckFailed": "failed",
"settings.diagnostics.cadPythonCheck": "Python packages (cadquery, trimesh)",
"settings.diagnostics.meshPythonCheck": "Python packages (trimesh, numpy, networkx, collada)",
"settings.diagnostics.freecadCmdCheck": "FreeCADCmd launch probe",
"settings.diagnostics.obj2gltfCheck": "obj2gltf launch probe",
"settings.diagnostics.fbx2gltfCheck": "FBX2glTF launch probe",
// Performance
"settings.canvasHeight": "Default canvas height",
"settings.canvasHeight.desc": "Default height (px) for inline model previews. Range: 200800.",
"settings.autoRotateSpeed": "Auto-rotate speed",
"settings.autoRotateSpeed.desc": "Rotation speed when auto-rotate is enabled. Range: 0.12.0.",
"settings.renderQuality": "Render quality",
"settings.renderQuality.desc": "Higher quality uses more GPU resources. Affects anti-aliasing and resolution.",
"settings.renderScale": "Resolution scale",
"settings.renderScale.desc": "Render resolution multiplier. 1.0 = native, 0.5 = half, 2.0 = double (supersampling). Range: 0.252.0.",
// Model load feedback
"modelLoad.warningTitle": "Model preview unavailable",
"modelLoad.warningMessage": "{ext} files need the {converterName} converter enabled in plugin settings before they can load.",
"modelLoad.warningHint": "Enable the matching converter in plugin settings, then reload this file.",
"modelLoad.mobileWarningMessage": "{ext} files need local conversion tools that are unavailable on iOS, iPadOS, and Android.",
"modelLoad.mobileWarningHint": "Open this file on desktop, or convert it to GLB, GLTF, OBJ, STL, or PLY first.",
"modelLoad.errorTitle": "Couldn't display this model",
"modelLoad.errorMessage": "Failed to load: {reason}",
"modelLoad.errorHint": "Check the file format or open the developer console for details.",
// Heading pin badge
"headingPin.showSingle": "Show linked pin",
"headingPin.showMultiple": "Show linked pins",
"headingPin.linkedTo": "Pin linked to: {models}",
// Helper toolbar
"helper.resetViewLabel": "Reset view",
"helper.resetViewDone": "Reset",
"helper.copyModelInfoLabel": "Copy model info as Markdown",
"helper.copySelectedPartInfoLabel": "Copy selected part info",
"helper.noSelectedPart": "Select a part first",
"helper.copied": "Copied!",
"helper.failed": "Failed",
"helper.toggleWireframeLabel": "Toggle wireframe",
"helper.wireframeOn": "Wireframe",
"helper.wireframeOff": "Solid",
"helper.toggleAxesLabel": "Toggle orientation axes",
"helper.axesOn": "Axes on",
"helper.axesOff": "Axes off",
"helper.toggleBoundingBoxLabel": "Toggle bounding box",
"helper.boundingBoxOn": "Bounding box on",
"helper.boundingBoxOff": "Bounding box off",
"helper.toggleFocusSelectionLabel": "Focus selected part",
"helper.focusSelectionOn": "Focus mode on",
"helper.focusSelectionOff": "Focus mode off",
"helper.toggleDisassemblyLabel": "Toggle disassembly mode",
"helper.disassemblyOn": "Disassembly on",
"helper.disassemblyOff": "Disassembly off",
"helper.resetPartsLabel": "Reset disassembled parts",
"helper.partsReset": "Parts reset",
"helper.changeResolutionLabel": "Change resolution",
"helper.resolutionValue": "Resolution: {value}",
"helper.toggleAnimationLabel": "Play or pause animation",
"helper.playing": "Playing",
"helper.paused": "Paused",
"helper.toggleMeasurementLabel": "Toggle distance measurement",
"helper.measurementOn": "Measurement on",
"helper.measurementOff": "Measurement off",
"helper.clearMeasurementsLabel": "Clear measurements",
"helper.measurementsCleared": "Cleared",
"helper.calibrateLabel": "Calibrate measurement scale",
"helper.calibrateTitle": "Measurement Calibration",
"helper.calibrateCurrent": "Current size:",
"helper.calibrateReal": "Real size:",
"helper.calibrateLock": "Lock ratio",
"helper.calibrateApply": "Apply",
"helper.calibrateReset": "Reset",
"helper.calibrated": "Scale applied",
"helper.calibrateResetDone": "Scale reset",
"helper.calibrateOpen": "Calibration panel opened",
"helper.calibrateClose": "Calibration panel closed",
"helper.removePreviewLabel": "Remove preview",
"helper.copySnapshotLabel": "Copy snapshot",
"helper.saveSnapshotLabel": "Save snapshot to vault",
"helper.saved": "Saved!",
"helper.downloadSnapshotLabel": "Download snapshot",
"helper.downloaded": "Downloaded!",
"helper.toggleAnnotationLabel": "Toggle annotation mode",
"helper.toggleAnnotationsVisibilityLabel": "Show or hide annotations",
"helper.annotateOn": "Annotation mode on",
"helper.annotateOff": "Annotation mode off",
"helper.annotationsVisible": "Annotations shown",
"helper.annotationsHidden": "Annotations hidden",
"helper.enableInteractionLabel": "Enable touch interaction",
"helper.disableInteractionLabel": "Return to scroll mode",
"helper.interactionOn": "Model interaction on",
"helper.interactionOff": "Scroll mode on",
"helper.showMoreActionsLabel": "Show more actions",
"helper.hideMoreActionsLabel": "Hide extra actions",
"helper.moreActionsShown": "More actions shown",
"helper.moreActionsHidden": "Extra actions hidden",
"helper.interactAction": "Interact",
"helper.scrollAction": "Scroll",
// Workbench and views
"workbench.emptyTitle": "No model",
"workbench.emptyText": "Use the \"import 3D model\" command to load a GLB, GLTF, STL, OBJ, or PLY file.",
"workbench.modelTitle": "Model",
"workbench.studioTitle": "AI Model Workbench",
"workbench.studioTagline": "Inspect, annotate, and turn 3D assets into linked notes.",
"workbench.navLabel": "Workbench sections",
"workbench.navGallery": "Gallery",
"workbench.navLibrary": "Library",
"workbench.navNotebooks": "Notebooks",
"workbench.navSettings": "Settings",
"workbench.sourcesTitle": "Model sources",
"workbench.layersTitle": "Review layers",
"workbench.viewModeTitle": "View mode",
"workbench.modeMesh": "Mesh view",
"workbench.modeFocus": "Focus selection",
"workbench.modeMeshShort": "Mesh",
"workbench.modeFocusShort": "Focus",
"workbench.previewViewsTitle": "Preview views",
"workbench.connectionsTitle": "Knowledge connections",
"workbench.currentModelLabel": "Current model",
"workbench.noReportYet": "No report note yet",
"workbench.noIndexYet": "No knowledge index yet. Generate a knowledge note first.",
"workbench.noModelLoaded": "No model loaded",
"workbench.disassemblyTitle": "Disassembly",
"workbench.explodeLabel": "Explode",
"workbench.summaryTitle": "Summary",
"workbench.meshesLabel": "Meshes",
"workbench.splatsLabel": "Splats",
"workbench.trianglesLabel": "Triangles",
"workbench.verticesLabel": "Vertices",
"workbench.materialsLabel": "Materials",
"workbench.boundingSizeLabel": "Bounds",
"workbench.centerLabel": "Center",
"workbench.selectedPartTitle": "Selected Part",
"workbench.partMeshLabel": "Mesh",
"workbench.noSelectedPart": "Click a model part to inspect it here.",
"workbench.tagsTitle": "Tags",
"workbench.noTagsYet": "No tags yet",
"workbench.addTagPlaceholder": "Add tag...",
"workbench.addTagAction": "Add",
"workbench.annotationsTitle": "Annotations",
"workbench.exitAnnotate": "Exit annotate",
"workbench.annotate": "Annotate",
"workbench.annotateHintActive": "Click the model to add a label · press Esc to exit",
"workbench.annotateHintActiveMobile": "Tap the model to add a label. Switch back to Scroll when you want to move through the note again.",
"workbench.pinCount": "{count} pin(s)",
"workbench.editAction": "Edit",
"workbench.deleteAction": "Delete",
"workbench.resetViewAction": "Reset view",
"workbench.insertInfoAction": "Insert info",
"workbench.insertGalleryAction": "Insert Gallery",
"workbench.insertCompareAction": "Insert Compare",
"workbench.playAction": "Play",
"workbench.pauseAction": "Pause",
"workbench.saveProfileAction": "Save profile",
"workbench.generateNoteAction": "Generate note",
"workbench.openNoteAction": "Open note",
"workbench.openIndexAction": "Open index",
"workbench.recordTitle": "Specimen card",
"workbench.recordSubtitle": "Current asset profile",
"workbench.notesTitle": "Analysis notes",
"workbench.whereTitle": "Where it connects",
"workbench.noteReady": "Linked note ready",
"workbench.indexReady": "Knowledge index ready",
"workbench.notePending": "Linked note pending",
"workbench.analysisLabel": "Analysis",
"workbench.settingsUnavailable": "Open this plugin from Obsidian settings to change workbench options.",
"workbench.profileSaved": "Profile saved",
"workbench.viewReset": "View reset",
"workbench.infoInserted": "Model info inserted",
"workbench.infoCopied": "Model info copied",
"workbench.templateInserted": "Template inserted",
"workbench.templateCopied": "Template copied",
"workbench.mobileHint": "Mobile tip: tap Interact to move the model, then switch back to Scroll to keep reading the note.",
"workbench.mobileHintInteractive": "Interaction mode is on. Switch back to Scroll when you want to move through the note again.",
"directView.mobileHint": "Mobile tip: use the toolbar Interact button to switch between model interaction and note scrolling.",
"directWorkbench.modelLoadInterrupted": "Model load was interrupted by a newer request.",
"directWorkbench.backendLabel": "Backend",
"directWorkbench.routeLabel": "Route",
"directWorkbench.performanceLabel": "Performance",
"directWorkbench.partCandidatesLabel": "Part candidates",
"directWorkbench.knowledgeTitle": "Knowledge",
"directWorkbench.registeredTitle": "Registered part matches",
"directWorkbench.registeredLoading": "Checking...",
"directWorkbench.registeredCount": "{count} match(es)",
"directWorkbench.registeredEmpty": "No cross-model part match yet",
"directWorkbench.registeredUnavailable": "Part evidence unavailable",
"directWorkbench.registeredOpen": "Open",
"directWorkbench.registeredOpenNote": "Note",
"directWorkbench.registeredOpenModel": "Model",
"directWorkbench.registeredSourceModel": "From {model}",
"directWorkbench.registeredTargetPartNote": "Opens matched part note",
"directWorkbench.registeredTargetSourceModel": "Opens source model",
"directWorkbench.registeredTargetUnavailable": "No linked target",
"workbench.fileNotFound": "File not found: {path}",
"annotation.selectColor": "Select color {color}",
"annotation.sectionEmpty": "Section is empty.",
"modal.selectModel": "Select a 3D model...",
"main.commandImportModel": "Import a 3D model",
"main.commandGenerateNote": "Generate knowledge note",
"main.commandOpenKnowledgeIndex": "Open knowledge index",
"main.commandClearConversionCache": "Clear conversion cache",
"main.commandCheckConverters": "Check converters",
"main.commandCopyDiagnostics": "Copy diagnostics report",
"main.converterDiagnosticsMobileUnavailable": "Converter diagnostics are only available on desktop. On iOS, iPadOS, and Android, direct formats can still load.",
"main.diagnosticsCopied": "AI Model Workbench diagnostics copied to clipboard.",
"main.diagnosticsCopyFailed": "Couldn't copy diagnostics. A sanitized diagnostics note was created instead.",
// Inline code block and loading
"codeBlock.noModelPathOrConfig": "No model path or config specified.",
"codeBlock.jsonParseError": "JSON parse error: {error}",
"codeBlock.jsonParseLine": " (line {line})",
"codeBlock.noModelsInConfig": "No models specified in config.",
"codeBlock.unsupportedFormat": "Unsupported format: {ext}. Supported: {formats}",
"codeBlock.splatDisabled": "SPLAT preview is disabled in packaged builds. Local-only .splat support is planned first; .spz/.sog need locally bundled decoders before reevaluation.",
"codeBlock.noConfigSpecified": "No config specified.",
"codeBlock.noModelsSpecified": "No models specified.",
"codeBlock.mobileHint": "Mobile tip: use Interact to manipulate the model, then switch back to Scroll to keep moving through the note.",
"codeBlock.renderingGrid": "Rendering grid...",
"codeBlock.composeRequiresSections": "\"compose\" preset requires a \"sections\" array.",
"codeBlock.composeNoValidSections": "Compose: no valid sections.",
"codeBlock.unknownPreset": "Unknown preset: \"{preset}\". Available: compare, showcase, explode, timeline, compose",
"codeBlock.presetRequiresModels": "Preset \"{preset}\" requires {min}-{max} models, got {count}.",
"codeBlock.gridFailed": "Grid failed: {reason}",
"livePreview.mobileHint": "Mobile tip: switch between Interact and Scroll depending on whether you want to move the model or keep reading.",
"loading.default": "Loading...",
"loading.preparingModel": "Preparing model...",
"loading.loadingModel": "Loading model...",
} as const;
export type TranslationKey = keyof typeof en;
export const en = {
// Section headers
"settings.title": "AI 3d model workbench",
"settings.folders": "Folders",
"settings.behavior": "Behavior",
"settings.converters": "Converters",
"settings.converterMenu": "Model converters",
"settings.converterMenu.desc": "Closed by default. Open this section only when you want to manually enable an optional local conversion route.",
"settings.environmentInspector": "Environment inspector",
"settings.environmentInspector.desc": "Closed by default. Open this section when you need to configure command paths or run environment checks.",
"settings.paths": "Converter paths",
"settings.diagnostics": "Converter command diagnostics",
"settings.performance": "Performance & display",
"settings.mobileSupport": "Mobile support",
"settings.knowledgeGeneration": "Knowledge generation",
// Folders
"settings.sourceModelFolder": "Source model folder",
"settings.sourceModelFolder.desc": "Vault folder where source model files are stored.",
"settings.reportFolder": "Report folder",
"settings.reportFolder.desc": "Vault folder where generated knowledge notes are saved.",
"settings.partFolder": "Part notes folder",
"settings.partFolder.desc": "Vault folder where generated part note drafts are saved.",
"settings.snapshotFolder": "Snapshot folder",
"settings.snapshotFolder.desc": "Vault folder where exported snapshots are saved.",
// Behavior
"settings.autoGenerateKnowledgeNotes": "Auto-generate knowledge notes",
"settings.autoGenerateKnowledgeNotes.desc": "Reserved for a future automation flow. For now, generate notes manually from the command palette.",
"settings.annotationPreviewMode": "Annotation preview mode",
"settings.annotationPreviewMode.desc": "Choose how bound note previews render in annotation popovers and the editor.",
"settings.annotationPreviewMode.plainText": "Plain text",
"settings.annotationPreviewMode.markdown": "Markdown",
"settings.annotationDisplayMode": "Annotation display mode",
"settings.annotationDisplayMode.desc": "Choose how bookmark pins appear over the model.",
"settings.annotationDisplayMode.snippet": "Full snippet",
"settings.annotationDisplayMode.surface": "Single surface",
"settings.annotationDisplayMode.dot": "Single dot",
"settings.previewRendererRollout": "Preview compatibility mode",
"settings.previewRendererRollout.desc": "Controls how widely the Three.js preview path is used for single-model previews (GLB, GLTF, STL, PLY, OBJ). Switch back to Compatibility mode if pin projection, occlusion, edit pins, snapshots, or toolbar behavior regress. 3dgrid is not affected by this setting.",
"settings.previewRendererRollout.babylonSafe": "Compatibility mode",
"settings.previewRendererRollout.readonly": "Reading surfaces only",
"settings.previewRendererRollout.direct": "Reading + file view (Recommended)",
"settings.useThreeRenderer": "Use Three.js renderer",
"settings.useThreeRenderer.desc": "Toggle between Three.js (faster, lighter) and Babylon.js (full compatibility) for single-model previews. Three.js supports GLB/GLTF/STL/PLY/OBJ. 3dgrid always uses Babylon.js.",
"settings.experimentalThreeWorkbench": "Experimental Three workbench",
"settings.experimentalThreeWorkbench.desc": "Try the Three.js workbench path for direct GLB/GLTF files only. If loading fails, the file view falls back to Babylon.js automatically.",
"settings.autoRotateDefault": "Auto-rotate by default",
"settings.autoRotateDefault.desc": "Start model previews with auto-rotation enabled.",
"settings.snapshotNaming": "Snapshot naming",
"settings.snapshotNaming.desc": "How exported snapshot files are named.",
"settings.snapshotNaming.modelName": "Model name + timestamp",
"settings.snapshotNaming.timestamp": "Timestamp only",
"settings.logLevel": "Log level",
"settings.logLevel.desc": "Controls plugin runtime log verbosity in the developer console.",
"settings.language": "Language",
"settings.language.desc": "Display language for plugin settings. Takes effect immediately.",
"settings.analysisMode": "AI drafting mode",
"settings.analysisMode.desc": "Controls whether knowledge-note generation stays local or also requests a sanitized remote draft. Raw model upload is blocked by the current client.",
"settings.analysisMode.local": "Local evidence only",
"settings.analysisMode.hybrid": "Local evidence + remote draft",
"settings.analysisMode.remote": "Remote draft from evidence",
"settings.serviceBaseUrl": "Draft service URL",
"settings.serviceBaseUrl.desc": "Optional base URL for a service that accepts POST /draft-note. Leave empty to keep all drafting local.",
"settings.sendGeometrySummaryToRemote": "Send geometry summary",
"settings.sendGeometrySummaryToRemote.desc": "Allow sanitized mesh counts, bounds, part candidates, annotation coordinates, and nearest-part links to be included in remote draft input.",
"settings.sendPreviewImagesToRemote": "Send preview image references",
"settings.sendPreviewImagesToRemote.desc": "Allow generated preview image paths to be listed in the remote draft input. Image bytes are not uploaded by this client.",
"settings.sendRawModelToRemote": "Send raw model file",
"settings.sendRawModelToRemote.desc": "Reserved for future explicit upload support. If enabled manually, remote draft requests are blocked instead of uploading the model.",
// Converters
"settings.enableCad": "Enable cad conversion for step, iges, and brep files",
"settings.enableCad.desc": "Enable cad conversion for step, iges, and brep formats. Requires cadquery and trimesh in your python environment.",
"settings.enableObj2gltf": "Enable obj2gltf converter (experimental)",
"settings.enableObj2gltf.desc": "Keep obj direct loading as the default. Enable this only if you want an optional local normalization route through obj2gltf.",
"settings.preferObj2gltf": "Prefer obj2gltf for obj",
"settings.preferObj2gltf.desc": "Recommended default is off. Turn this on only when you want normalized output files or direct obj loading is not good enough.",
"settings.enableFbx2gltf": "Enable FBX2glTF converter",
"settings.enableFbx2gltf.desc": "Enable conversion for fbx files via FBX2glTF. Requires the FBX2glTF binary installed locally.",
"settings.enableMesh": "Enable mesh conversion for 3mf and dae files",
"settings.enableMesh.desc": "Enable conversion for 3mf and dae formats via python trimesh. Requires trimesh, numpy, networkx, and pycollada in your python environment.",
"settings.enableSldprt": "Enable sldprt conversion for SolidWorks files",
"settings.enableSldprt.desc": "Enable conversion for SolidWorks sldprt files via FreeCAD. Requires FreeCAD installed locally.",
"settings.mobileSupport.desc": "On iOS, iPadOS, and Android, direct formats like GLB, GLTF, STL, OBJ, and PLY are supported. Local converter settings and diagnostics remain desktop-only.",
// Converter paths
"settings.pythonCmd": "Path to the python command for cad conversion",
"settings.pythonCmd.desc": "Optional path to the python command used for cad conversion. Windows usually uses py. macOS and Linux usually use python3. Overrides auto-discovery when set.",
"settings.freecadCmd": "Path to the FreeCAD command for sldprt conversion",
"settings.freecadCmd.desc": "Optional path to the FreeCAD command used for SolidWorks file conversion. Windows usually uses FreeCADCmd.exe, macOS usually uses FreeCADCmd, and Linux usually uses freecadcmd. Overrides auto-discovery when set.",
"settings.obj2gltfCmd": "Path to the obj2gltf command",
"settings.obj2gltfCmd.desc": "Optional path to the obj2gltf command. Windows usually uses obj2gltf.cmd, and macOS and Linux usually use obj2gltf. Overrides auto-discovery when set.",
"settings.fbx2gltfCmd": "FBX2glTF command path",
"settings.fbx2gltfCmd.desc": "Optional path to the FBX2glTF command. Windows usually uses FBX2glTF.exe, and macOS and Linux usually use FBX2glTF. Overrides auto-discovery when set.",
"settings.assimpCmd": "Path to the python command for 3mf and dae conversion",
"settings.assimpCmd.desc": "Optional path to the python command used for 3mf and dae conversion. Windows usually uses py. macOS and Linux usually use python3. Overrides auto-discovery when set.",
// Diagnostics
"settings.diagnostics.desc": "Shows the exact executable path the plugin would use right now and runs lightweight self-checks for Python environments and converter CLIs.",
"settings.diagnostics.idle": "Diagnostics are off by default. Click Check now to run them manually.",
"settings.diagnostics.checkNow": "Check now",
"settings.diagnostics.checking": "Checking...",
"settings.diagnostics.refreshed": "Converter command diagnostics refreshed.",
"settings.diagnostics.checkingAvailability": "Checking converter command availability...",
"settings.diagnostics.available": "available",
"settings.diagnostics.notFound": "not found",
"settings.diagnostics.sourceLabel": "Source",
"settings.diagnostics.commandLabel": "Command",
"settings.diagnostics.resolvedPathLabel": "Resolved path",
"settings.diagnostics.selfCheckLabel": "Self-check",
"settings.diagnostics.selfCheckOk": "passed",
"settings.diagnostics.selfCheckFailed": "failed",
"settings.diagnostics.cadPythonCheck": "Python packages (cadquery, trimesh)",
"settings.diagnostics.meshPythonCheck": "Python packages (trimesh, numpy, networkx, collada)",
"settings.diagnostics.freecadCmdCheck": "FreeCADCmd launch probe",
"settings.diagnostics.obj2gltfCheck": "obj2gltf launch probe",
"settings.diagnostics.fbx2gltfCheck": "FBX2glTF launch probe",
// Performance
"settings.canvasHeight": "Default canvas height",
"settings.canvasHeight.desc": "Default height (px) for inline model previews. Range: 200800.",
"settings.autoRotateSpeed": "Auto-rotate speed",
"settings.autoRotateSpeed.desc": "Rotation speed when auto-rotate is enabled. Range: 0.12.0.",
"settings.renderQuality": "Render quality",
"settings.renderQuality.desc": "Higher quality uses more GPU resources. Affects anti-aliasing and resolution.",
"settings.renderScale": "Resolution scale",
"settings.renderScale.desc": "Render resolution multiplier. 1.0 = native, 0.5 = half, 2.0 = double (supersampling). Range: 0.252.0.",
// Model load feedback
"modelLoad.warningTitle": "Model preview unavailable",
"modelLoad.warningMessage": "{ext} files need the {converterName} converter enabled in plugin settings before they can load.",
"modelLoad.warningHint": "Enable the matching converter in plugin settings, then reload this file.",
"modelLoad.mobileWarningMessage": "{ext} files need local conversion tools that are unavailable on iOS, iPadOS, and Android.",
"modelLoad.mobileWarningHint": "Open this file on desktop, or convert it to GLB, GLTF, OBJ, STL, or PLY first.",
"modelLoad.errorTitle": "Couldn't display this model",
"modelLoad.errorMessage": "Failed to load: {reason}",
"modelLoad.errorHint": "Check the file format or open the developer console for details.",
// Heading pin badge
"headingPin.showSingle": "Show linked pin",
"headingPin.showMultiple": "Show linked pins",
"headingPin.linkedTo": "Pin linked to: {models}",
// Helper toolbar
"helper.resetViewLabel": "Reset view",
"helper.resetViewDone": "Reset",
"helper.copyModelInfoLabel": "Copy model info as Markdown",
"helper.copySelectedPartInfoLabel": "Copy selected part info",
"helper.noSelectedPart": "Select a part first",
"helper.copied": "Copied!",
"helper.failed": "Failed",
"helper.toggleWireframeLabel": "Toggle wireframe",
"helper.wireframeOn": "Wireframe",
"helper.wireframeOff": "Solid",
"helper.toggleAxesLabel": "Toggle orientation axes",
"helper.axesOn": "Axes on",
"helper.axesOff": "Axes off",
"helper.toggleBoundingBoxLabel": "Toggle bounding box",
"helper.boundingBoxOn": "Bounding box on",
"helper.boundingBoxOff": "Bounding box off",
"helper.toggleFocusSelectionLabel": "Focus selected part",
"helper.focusSelectionOn": "Focus mode on",
"helper.focusSelectionOff": "Focus mode off",
"helper.toggleDisassemblyLabel": "Toggle disassembly mode",
"helper.disassemblyOn": "Disassembly on",
"helper.disassemblyOff": "Disassembly off",
"helper.resetPartsLabel": "Reset disassembled parts",
"helper.partsReset": "Parts reset",
"helper.changeResolutionLabel": "Change resolution",
"helper.resolutionValue": "Resolution: {value}",
"helper.toggleAnimationLabel": "Play or pause animation",
"helper.playing": "Playing",
"helper.paused": "Paused",
"helper.toggleMeasurementLabel": "Toggle distance measurement",
"helper.measurementOn": "Measurement on",
"helper.measurementOff": "Measurement off",
"helper.clearMeasurementsLabel": "Clear measurements",
"helper.measurementsCleared": "Cleared",
"helper.calibrateLabel": "Calibrate measurement scale",
"helper.calibrateTitle": "Measurement Calibration",
"helper.calibrateCurrent": "Current size:",
"helper.calibrateReal": "Real size:",
"helper.calibrateLock": "Lock ratio",
"helper.calibrateApply": "Apply",
"helper.calibrateReset": "Reset",
"helper.calibrated": "Scale applied",
"helper.calibrateResetDone": "Scale reset",
"helper.calibrateOpen": "Calibration panel opened",
"helper.calibrateClose": "Calibration panel closed",
"helper.removePreviewLabel": "Remove preview",
"helper.copySnapshotLabel": "Copy snapshot",
"helper.saveSnapshotLabel": "Save snapshot to vault",
"helper.saved": "Saved!",
"helper.downloadSnapshotLabel": "Download snapshot",
"helper.downloaded": "Downloaded!",
"helper.toggleAnnotationLabel": "Toggle annotation mode",
"helper.toggleAnnotationsVisibilityLabel": "Show or hide annotations",
"helper.annotateOn": "Annotation mode on",
"helper.annotateOff": "Annotation mode off",
"helper.annotationsVisible": "Annotations shown",
"helper.annotationsHidden": "Annotations hidden",
"helper.enableInteractionLabel": "Enable touch interaction",
"helper.disableInteractionLabel": "Return to scroll mode",
"helper.interactionOn": "Model interaction on",
"helper.interactionOff": "Scroll mode on",
"helper.showMoreActionsLabel": "Show more actions",
"helper.hideMoreActionsLabel": "Hide extra actions",
"helper.moreActionsShown": "More actions shown",
"helper.moreActionsHidden": "Extra actions hidden",
"helper.interactAction": "Interact",
"helper.scrollAction": "Scroll",
// Workbench and views
"workbench.emptyTitle": "No model",
"workbench.emptyText": "Use the \"import 3D model\" command to load a GLB, GLTF, STL, OBJ, or PLY file.",
"workbench.modelTitle": "Model",
"workbench.studioTitle": "AI Model Workbench",
"workbench.studioTagline": "Inspect, annotate, and turn 3D assets into linked notes.",
"workbench.navLabel": "Workbench sections",
"workbench.navGallery": "Gallery",
"workbench.navLibrary": "Library",
"workbench.navNotebooks": "Notebooks",
"workbench.navSettings": "Settings",
"workbench.sourcesTitle": "Model sources",
"workbench.layersTitle": "Review layers",
"workbench.viewModeTitle": "View mode",
"workbench.modeMesh": "Mesh view",
"workbench.modeFocus": "Focus selection",
"workbench.modeMeshShort": "Mesh",
"workbench.modeFocusShort": "Focus",
"workbench.previewViewsTitle": "Preview views",
"workbench.connectionsTitle": "Knowledge connections",
"workbench.currentModelLabel": "Current model",
"workbench.noReportYet": "No report note yet",
"workbench.noIndexYet": "No knowledge index yet. Generate a knowledge note first.",
"workbench.noModelLoaded": "No model loaded",
"workbench.disassemblyTitle": "Disassembly",
"workbench.explodeLabel": "Explode",
"workbench.summaryTitle": "Summary",
"workbench.meshesLabel": "Meshes",
"workbench.splatsLabel": "Splats",
"workbench.trianglesLabel": "Triangles",
"workbench.verticesLabel": "Vertices",
"workbench.materialsLabel": "Materials",
"workbench.boundingSizeLabel": "Bounds",
"workbench.centerLabel": "Center",
"workbench.selectedPartTitle": "Selected Part",
"workbench.partMeshLabel": "Mesh",
"workbench.noSelectedPart": "Click a model part to inspect it here.",
"workbench.tagsTitle": "Tags",
"workbench.noTagsYet": "No tags yet",
"workbench.addTagPlaceholder": "Add tag...",
"workbench.addTagAction": "Add",
"workbench.annotationsTitle": "Annotations",
"workbench.exitAnnotate": "Exit annotate",
"workbench.annotate": "Annotate",
"workbench.annotateHintActive": "Click the model to add a label · press Esc to exit",
"workbench.annotateHintActiveMobile": "Tap the model to add a label. Switch back to Scroll when you want to move through the note again.",
"workbench.pinCount": "{count} pin(s)",
"workbench.editAction": "Edit",
"workbench.deleteAction": "Delete",
"workbench.resetViewAction": "Reset view",
"workbench.insertInfoAction": "Insert info",
"workbench.insertGalleryAction": "Insert Gallery",
"workbench.insertCompareAction": "Insert Compare",
"workbench.playAction": "Play",
"workbench.pauseAction": "Pause",
"workbench.saveProfileAction": "Save profile",
"workbench.generateNoteAction": "Generate note",
"workbench.openNoteAction": "Open note",
"workbench.openIndexAction": "Open index",
"workbench.recordTitle": "Specimen card",
"workbench.recordSubtitle": "Current asset profile",
"workbench.notesTitle": "Analysis notes",
"workbench.whereTitle": "Where it connects",
"workbench.noteReady": "Linked note ready",
"workbench.indexReady": "Knowledge index ready",
"workbench.notePending": "Linked note pending",
"workbench.analysisLabel": "Analysis",
"workbench.settingsUnavailable": "Open this plugin from Obsidian settings to change workbench options.",
"workbench.profileSaved": "Profile saved",
"workbench.viewReset": "View reset",
"workbench.infoInserted": "Model info inserted",
"workbench.infoCopied": "Model info copied",
"workbench.templateInserted": "Template inserted",
"workbench.templateCopied": "Template copied",
"workbench.mobileHint": "Mobile tip: tap Interact to move the model, then switch back to Scroll to keep reading the note.",
"workbench.mobileHintInteractive": "Interaction mode is on. Switch back to Scroll when you want to move through the note again.",
"directView.mobileHint": "Mobile tip: use the toolbar Interact button to switch between model interaction and note scrolling.",
"directWorkbench.modelLoadInterrupted": "Model load was interrupted by a newer request.",
"directWorkbench.backendLabel": "Backend",
"directWorkbench.routeLabel": "Route",
"directWorkbench.performanceLabel": "Performance",
"directWorkbench.partCandidatesLabel": "Part candidates",
"directWorkbench.knowledgeTitle": "Knowledge",
"directWorkbench.registeredTitle": "Registered part matches",
"directWorkbench.registeredLoading": "Checking...",
"directWorkbench.registeredCount": "{count} match(es)",
"directWorkbench.registeredEmpty": "No cross-model part match yet",
"directWorkbench.registeredUnavailable": "Part evidence unavailable",
"directWorkbench.registeredOpen": "Open",
"directWorkbench.registeredOpenNote": "Note",
"directWorkbench.registeredOpenModel": "Model",
"directWorkbench.registeredSourceModel": "From {model}",
"directWorkbench.registeredTargetPartNote": "Opens matched part note",
"directWorkbench.registeredTargetSourceModel": "Opens source model",
"directWorkbench.registeredTargetUnavailable": "No linked target",
"workbench.fileNotFound": "File not found: {path}",
"annotation.selectColor": "Select color {color}",
"annotation.sectionEmpty": "Section is empty.",
"modal.selectModel": "Select a 3D model...",
"main.commandImportModel": "Import a 3D model",
"main.commandGenerateNote": "Generate knowledge note",
"main.commandOpenKnowledgeIndex": "Open knowledge index",
"main.commandClearConversionCache": "Clear conversion cache",
"main.commandCheckConverters": "Check converters",
"main.commandCopyDiagnostics": "Copy diagnostics report",
"main.converterDiagnosticsMobileUnavailable": "Converter diagnostics are only available on desktop. On iOS, iPadOS, and Android, direct formats can still load.",
"main.diagnosticsCopied": "AI Model Workbench diagnostics copied to clipboard.",
"main.diagnosticsCopyFailed": "Couldn't copy diagnostics. A sanitized diagnostics note was created instead.",
// Inline code block and loading
"codeBlock.noModelPathOrConfig": "No model path or config specified.",
"codeBlock.jsonParseError": "JSON parse error: {error}",
"codeBlock.jsonParseLine": " (line {line})",
"codeBlock.noModelsInConfig": "No models specified in config.",
"codeBlock.unsupportedFormat": "Unsupported format: {ext}. Supported: {formats}",
"codeBlock.splatDisabled": "SPLAT preview is disabled in packaged builds. Local-only .splat support is planned first; .spz/.sog need locally bundled decoders before reevaluation.",
"codeBlock.noConfigSpecified": "No config specified.",
"codeBlock.noModelsSpecified": "No models specified.",
"codeBlock.mobileHint": "Mobile tip: use Interact to manipulate the model, then switch back to Scroll to keep moving through the note.",
"codeBlock.renderingGrid": "Rendering grid...",
"codeBlock.composeRequiresSections": "\"compose\" preset requires a \"sections\" array.",
"codeBlock.composeNoValidSections": "Compose: no valid sections.",
"codeBlock.unknownPreset": "Unknown preset: \"{preset}\". Available: compare, showcase, explode, timeline, compose",
"codeBlock.presetRequiresModels": "Preset \"{preset}\" requires {min}-{max} models, got {count}.",
"codeBlock.gridFailed": "Grid failed: {reason}",
"livePreview.mobileHint": "Mobile tip: switch between Interact and Scroll depending on whether you want to move the model or keep reading.",
"loading.default": "Loading...",
"loading.preparingModel": "Preparing model...",
"loading.loadingModel": "Loading model...",
} as const;
export type TranslationKey = keyof typeof en;

View file

@ -1,345 +1,345 @@
import type { TranslationKey } from "./en";
export const zhCN: Record<TranslationKey, string> = {
// 区块标题
"settings.title": "AI 3D 模型工作台",
"settings.folders": "文件夹",
"settings.behavior": "行为",
"settings.converters": "转换器",
"settings.converterMenu": "模型转换器",
"settings.converterMenu.desc": "默认收起。仅在你需要手动启用某条本地转换路线时再展开。",
"settings.environmentInspector": "环境检查器",
"settings.environmentInspector.desc": "默认收起。仅在需要配置命令路径或手动执行环境检查时再展开。",
"settings.paths": "转换器路径",
"settings.diagnostics": "转换器命令诊断",
"settings.performance": "性能与显示",
"settings.mobileSupport": "移动端支持",
"settings.knowledgeGeneration": "知识生成",
// 文件夹
"settings.sourceModelFolder": "源模型文件夹",
"settings.sourceModelFolder.desc": "存放源 3D 模型的库文件夹。",
"settings.reportFolder": "报告文件夹",
"settings.reportFolder.desc": "保存生成的知识笔记的库文件夹。",
"settings.partFolder": "部件笔记文件夹",
"settings.partFolder.desc": "保存生成的部件笔记草稿的库文件夹。",
"settings.snapshotFolder": "快照文件夹",
"settings.snapshotFolder.desc": "保存导出快照的库文件夹。",
// 行为
"settings.autoGenerateKnowledgeNotes": "自动生成知识笔记",
"settings.autoGenerateKnowledgeNotes.desc": "预留给后续自动化流程。当前请通过命令或工作台按钮手动生成知识笔记。",
"settings.annotationPreviewMode": "标注预览模式",
"settings.annotationPreviewMode.desc": "选择标注绑定笔记在悬浮预览和编辑器中的显示方式。",
"settings.annotationPreviewMode.plainText": "纯文本",
"settings.annotationPreviewMode.markdown": "Markdown",
"settings.annotationDisplayMode": "标注显示模式",
"settings.annotationDisplayMode.desc": "选择模型上书签标注的显示方式。",
"settings.annotationDisplayMode.snippet": "完整片段",
"settings.annotationDisplayMode.surface": "单个标签面",
"settings.annotationDisplayMode.dot": "单个圆点",
"settings.previewRendererRollout": "预览兼容模式",
"settings.previewRendererRollout.desc": "控制单模型预览GLB、GLTF、STL、PLY、OBJ中 Three.js 渲染路径的启用范围。只要出现 pin 投影、遮挡、编辑态 pin、快照或工具栏行为回退就切回“兼容优先”。workbench 和 3dgrid 不受这个设置影响。",
"settings.previewRendererRollout.babylonSafe": "兼容优先",
"settings.previewRendererRollout.readonly": "仅阅读场景",
"settings.previewRendererRollout.direct": "阅读 + 文件视图(推荐)",
"settings.useThreeRenderer": "使用 Three.js 渲染器",
"settings.useThreeRenderer.desc": "在 Three.js更快、更轻量和 Babylon.js完全兼容之间切换单模型预览渲染器。Three.js 支持 GLB/GLTF/STL/PLY/OBJ。工作台和 3dgrid 始终使用 Babylon.js。",
"settings.experimentalThreeWorkbench": "实验性 Three 工作台",
"settings.experimentalThreeWorkbench.desc": "仅对直读 GLB/GLTF 文件尝试使用 Three.js 工作台路径。加载失败时,文件视图会自动回退到 Babylon.js。",
"settings.autoRotateDefault": "默认自动旋转",
"settings.autoRotateDefault.desc": "启动 3D 预览时默认开启自动旋转。",
"settings.snapshotNaming": "快照命名",
"settings.snapshotNaming.desc": "导出快照文件的命名方式。",
"settings.snapshotNaming.modelName": "模型名 + 时间戳",
"settings.snapshotNaming.timestamp": "仅时间戳",
"settings.logLevel": "日志级别",
"settings.logLevel.desc": "控制插件在开发者控制台中的日志详细程度。",
"settings.language": "语言",
"settings.language.desc": "插件设置界面的显示语言。立即生效。",
"settings.analysisMode": "AI 草稿模式",
"settings.analysisMode.desc": "控制知识笔记生成保持本地,还是额外请求经过裁剪的远程草稿。当前客户端会阻止原始模型上传。",
"settings.analysisMode.local": "仅本地证据",
"settings.analysisMode.hybrid": "本地证据 + 远程草稿",
"settings.analysisMode.remote": "基于证据的远程草稿",
"settings.serviceBaseUrl": "草稿服务 URL",
"settings.serviceBaseUrl.desc": "可选的草稿服务基础地址,服务需接收 POST /draft-note。留空时所有草稿输入都保留在本地。",
"settings.sendGeometrySummaryToRemote": "发送几何摘要",
"settings.sendGeometrySummaryToRemote.desc": "允许把经过裁剪的网格数量、包围盒、部件候选、标注坐标和最近部件关联加入远程草稿输入。",
"settings.sendPreviewImagesToRemote": "发送预览图引用",
"settings.sendPreviewImagesToRemote.desc": "允许在远程草稿输入中列出生成的预览图路径。当前客户端不会上传图片字节。",
"settings.sendRawModelToRemote": "发送原始模型文件",
"settings.sendRawModelToRemote.desc": "预留给未来显式上传支持。若手动开启,远程草稿请求会被阻止,不会上传模型。",
// 转换器
"settings.enableCad": "启用 CAD 转换器 (STEP/IGES/BREP)",
"settings.enableCad.desc": "启用 STEP/IGES/BREP 格式的 CAD 转换路线,通过 Python CadQuery (OpenCASCADE)。需要pip install cadquery trimesh",
"settings.enableObj2gltf": "启用 obj2gltf 转换器(实验性)",
"settings.enableObj2gltf.desc": "默认使用 OBJ 直接加载。仅在需要本地标准化 GLB 输出时启用。",
"settings.preferObj2gltf": "OBJ 优先使用 obj2gltf",
"settings.preferObj2gltf.desc": "默认关闭。仅在需要标准化 GLB 输出或直接 OBJ 加载效果不佳时开启。",
"settings.enableFbx2gltf": "启用 FBX2glTF 转换器",
"settings.enableFbx2gltf.desc": "启用 FBX 文件通过 FBX2glTF 转换。需要本地安装 FBX2glTF 二进制文件。",
"settings.enableMesh": "启用网格转换器 (3MF/DAE)",
"settings.enableMesh.desc": "启用 3MF 和 DAE (Collada) 格式的转换路线,通过 Python trimesh。需要安装 Python 和 trimesh (pip install trimesh numpy networkx pycollada)。",
"settings.enableSldprt": "启用 SLDPRT 转换器 (SolidWorks)",
"settings.enableSldprt.desc": "启用 SolidWorks .sldprt 文件通过 FreeCAD 转换。需要安装 FreeCAD (https://www.freecad.org/downloads.php)。",
"settings.mobileSupport.desc": "在 iOS、iPadOS 和 Android 上GLB、GLTF、STL、OBJ、PLY 这类直读格式可用。本地转换器设置和命令诊断仍仅支持桌面端。",
// 转换器路径
"settings.pythonCmd": "Python 命令路径CAD 用)",
"settings.pythonCmd.desc": "可选的 Python 命令路径,用于 CAD 转换。Windows 通常用 pymacOS 和 Linux 通常用 python3。设置后覆盖自动发现和 AI3D_FREECAD_CMD。",
"settings.freecadCmd": "FreeCAD 命令路径SLDPRT 用)",
"settings.freecadCmd.desc": "可选的 FreeCAD 命令路径,用于 SolidWorks 文件转换。Windows 通常用 FreeCADCmd.exemacOS 通常用 FreeCADCmdLinux 通常用 freecadcmd。设置后覆盖自动发现和 AI3D_FREECADCMD。",
"settings.obj2gltfCmd": "obj2gltf 命令路径",
"settings.obj2gltfCmd.desc": "可选的 obj2gltf 命令路径。Windows 通常用 obj2gltf.cmdmacOS 和 Linux 通常用 obj2gltf。设置后覆盖自动发现和 AI3D_OBJ2GLTF_CMD。",
"settings.fbx2gltfCmd": "FBX2glTF 命令路径",
"settings.fbx2gltfCmd.desc": "可选的 FBX2glTF 命令路径。Windows 通常用 FBX2glTF.exemacOS 和 Linux 通常用 FBX2glTF。设置后覆盖自动发现和 AI3D_FBX2GLTF_CMD。",
"settings.assimpCmd": "Python 命令路径3MF/DAE 用)",
"settings.assimpCmd.desc": "可选的 Python 命令路径,用于 3MF 和 DAE 转换。Windows 通常用 pymacOS 和 Linux 通常用 python3。设置后覆盖自动发现和 AI3D_ASSIMP_CMD。",
// 诊断
"settings.diagnostics.desc": "显示插件当前实际使用的可执行文件路径,并为 Python 环境和转换器命令执行轻量自检。",
"settings.diagnostics.idle": "环境检查默认关闭。点击“立即检查”后才会执行。",
"settings.diagnostics.checkNow": "立即检查",
"settings.diagnostics.checking": "检查中...",
"settings.diagnostics.refreshed": "AI 3D 转换器命令诊断已刷新。",
"settings.diagnostics.checkingAvailability": "正在检查转换器命令可用性...",
"settings.diagnostics.available": "可用",
"settings.diagnostics.notFound": "未找到",
"settings.diagnostics.sourceLabel": "来源",
"settings.diagnostics.commandLabel": "命令",
"settings.diagnostics.resolvedPathLabel": "解析路径",
"settings.diagnostics.selfCheckLabel": "自检",
"settings.diagnostics.selfCheckOk": "通过",
"settings.diagnostics.selfCheckFailed": "失败",
"settings.diagnostics.cadPythonCheck": "Python 包cadquery、trimesh",
"settings.diagnostics.meshPythonCheck": "Python 包trimesh、numpy、networkx、collada",
"settings.diagnostics.freecadCmdCheck": "FreeCADCmd 启动探测",
"settings.diagnostics.obj2gltfCheck": "obj2gltf 启动探测",
"settings.diagnostics.fbx2gltfCheck": "FBX2glTF 启动探测",
// 性能
"settings.canvasHeight": "默认画布高度",
"settings.canvasHeight.desc": "内联 3D 预览的默认高度像素。范围200800。",
"settings.autoRotateSpeed": "自动旋转速度",
"settings.autoRotateSpeed.desc": "启用自动旋转时的旋转速度。范围0.12.0。",
"settings.renderQuality": "渲染质量",
"settings.renderQuality.desc": "更高质量使用更多 GPU 资源。影响抗锯齿和分辨率。",
"settings.renderScale": "渲染缩放",
"settings.renderScale.desc": "渲染分辨率倍数。1.0 = 原始0.5 = 一半2.0 = 双倍超采样。范围0.252.0。",
// 模型加载提示
"modelLoad.warningTitle": "暂时无法预览模型",
"modelLoad.warningMessage": "{ext} 文件需要先在插件设置中启用 {converterName} 转换器,才能加载。",
"modelLoad.warningHint": "请先在插件设置中启用对应转换器,然后重新加载当前文件。",
"modelLoad.mobileWarningMessage": "{ext} 文件需要本地转换工具,但这些工具在 iOS、iPadOS 和 Android 上不可用。",
"modelLoad.mobileWarningHint": "请在桌面端打开此文件,或先将它转换为 GLB、GLTF、OBJ、STL 或 PLY。",
"modelLoad.errorTitle": "无法显示这个模型",
"modelLoad.errorMessage": "加载失败:{reason}",
"modelLoad.errorHint": "请检查文件格式,或打开开发者控制台查看详细信息。",
// 标题 pin 徽标
"headingPin.showSingle": "显示关联标注",
"headingPin.showMultiple": "显示关联标注",
"headingPin.linkedTo": "关联到:{models}",
// 工具栏
"helper.resetViewLabel": "重置视图",
"helper.resetViewDone": "已重置",
"helper.copyModelInfoLabel": "复制模型信息为 Markdown",
"helper.copySelectedPartInfoLabel": "复制选中部件信息",
"helper.noSelectedPart": "请先点击一个部件",
"helper.copied": "已复制",
"helper.failed": "失败",
"helper.toggleWireframeLabel": "切换线框显示",
"helper.wireframeOn": "线框",
"helper.wireframeOff": "实体",
"helper.toggleAxesLabel": "切换方向坐标轴",
"helper.axesOn": "坐标轴已开启",
"helper.axesOff": "坐标轴已关闭",
"helper.toggleBoundingBoxLabel": "切换包围盒",
"helper.boundingBoxOn": "包围盒已开启",
"helper.boundingBoxOff": "包围盒已关闭",
"helper.toggleFocusSelectionLabel": "聚焦选中部件",
"helper.focusSelectionOn": "聚焦模式已开启",
"helper.focusSelectionOff": "聚焦模式已关闭",
"helper.toggleDisassemblyLabel": "切换分解模式",
"helper.disassemblyOn": "分解模式已开启",
"helper.disassemblyOff": "分解模式已关闭",
"helper.resetPartsLabel": "重置分解部件",
"helper.partsReset": "部件已重置",
"helper.changeResolutionLabel": "切换分辨率",
"helper.resolutionValue": "分辨率:{value}",
"helper.toggleAnimationLabel": "播放或暂停动画",
"helper.playing": "播放中",
"helper.paused": "已暂停",
"helper.toggleMeasurementLabel": "切换距离测量",
"helper.measurementOn": "测量已开启",
"helper.measurementOff": "测量已关闭",
"helper.clearMeasurementsLabel": "清除测量",
"helper.measurementsCleared": "已清除",
"helper.calibrateLabel": "校准测量比例",
"helper.calibrateTitle": "测量校准",
"helper.calibrateCurrent": "当前尺寸:",
"helper.calibrateReal": "真实尺寸:",
"helper.calibrateLock": "锁定比例",
"helper.calibrateApply": "应用",
"helper.calibrateReset": "重置",
"helper.calibrated": "比例已应用",
"helper.calibrateResetDone": "比例已重置",
"helper.calibrateOpen": "校准面板已打开",
"helper.calibrateClose": "校准面板已关闭",
"helper.removePreviewLabel": "移除预览",
"helper.copySnapshotLabel": "复制快照",
"helper.saveSnapshotLabel": "保存快照到仓库",
"helper.saved": "已保存",
"helper.downloadSnapshotLabel": "下载快照",
"helper.downloaded": "已下载",
"helper.toggleAnnotationLabel": "切换标注模式",
"helper.toggleAnnotationsVisibilityLabel": "显示或隐藏标注",
"helper.annotateOn": "标注模式已开启",
"helper.annotateOff": "标注模式已关闭",
"helper.annotationsVisible": "标注已显示",
"helper.annotationsHidden": "标注已隐藏",
"helper.enableInteractionLabel": "启用触控交互",
"helper.disableInteractionLabel": "切回滚动模式",
"helper.interactionOn": "模型交互已开启",
"helper.interactionOff": "滚动模式已开启",
"helper.showMoreActionsLabel": "显示更多操作",
"helper.hideMoreActionsLabel": "收起额外操作",
"helper.moreActionsShown": "已展开更多操作",
"helper.moreActionsHidden": "已收起额外操作",
"helper.interactAction": "交互",
"helper.scrollAction": "滚动",
// 工作台与视图
"workbench.emptyTitle": "暂无模型",
"workbench.emptyText": "使用“导入 3D 模型”命令加载 GLB、GLTF、STL、OBJ 或 PLY 文件。",
"workbench.modelTitle": "3D 模型",
"workbench.studioTitle": "AI 模型工作台",
"workbench.studioTagline": "检查、标注,并把 3D 资产整理成双链笔记。",
"workbench.navLabel": "工作台分区",
"workbench.navGallery": "画廊",
"workbench.navLibrary": "资料库",
"workbench.navNotebooks": "笔记本",
"workbench.navSettings": "设置",
"workbench.sourcesTitle": "模型来源",
"workbench.layersTitle": "审阅层",
"workbench.viewModeTitle": "视图模式",
"workbench.modeMesh": "网格视图",
"workbench.modeFocus": "聚焦选区",
"workbench.modeMeshShort": "网格",
"workbench.modeFocusShort": "聚焦",
"workbench.previewViewsTitle": "预览视图",
"workbench.connectionsTitle": "知识连接",
"workbench.currentModelLabel": "当前模型",
"workbench.noReportYet": "还没有报告笔记",
"workbench.noIndexYet": "还没有知识索引。请先生成知识笔记。",
"workbench.noModelLoaded": "尚未加载模型",
"workbench.disassemblyTitle": "分解",
"workbench.explodeLabel": "爆炸",
"workbench.summaryTitle": "摘要",
"workbench.meshesLabel": "网格",
"workbench.splatsLabel": "点云",
"workbench.trianglesLabel": "三角形",
"workbench.verticesLabel": "顶点",
"workbench.materialsLabel": "材质",
"workbench.boundingSizeLabel": "包围盒",
"workbench.centerLabel": "中心",
"workbench.selectedPartTitle": "当前选中部件",
"workbench.partMeshLabel": "网格",
"workbench.noSelectedPart": "点击模型中的部件后会显示详细信息。",
"workbench.tagsTitle": "标签",
"workbench.noTagsYet": "还没有标签",
"workbench.addTagPlaceholder": "添加标签...",
"workbench.addTagAction": "添加",
"workbench.annotationsTitle": "标注",
"workbench.exitAnnotate": "退出标注",
"workbench.annotate": "标注",
"workbench.annotateHintActive": "点击模型添加标签 · 按 Esc 退出",
"workbench.annotateHintActiveMobile": "点按模型添加标签。需要继续阅读时切回“滚动”。",
"workbench.pinCount": "{count} 个标注",
"workbench.editAction": "编辑",
"workbench.deleteAction": "删除",
"workbench.resetViewAction": "重置视图",
"workbench.insertInfoAction": "插入信息",
"workbench.insertGalleryAction": "插入 Gallery",
"workbench.insertCompareAction": "插入对比",
"workbench.playAction": "播放",
"workbench.pauseAction": "暂停",
"workbench.saveProfileAction": "保存配置",
"workbench.generateNoteAction": "生成笔记",
"workbench.openNoteAction": "打开笔记",
"workbench.openIndexAction": "打开索引",
"workbench.recordTitle": "标本卡",
"workbench.recordSubtitle": "当前资产档案",
"workbench.notesTitle": "分析札记",
"workbench.whereTitle": "关联位置",
"workbench.noteReady": "关联笔记已就绪",
"workbench.indexReady": "知识索引已就绪",
"workbench.notePending": "关联笔记待生成",
"workbench.analysisLabel": "分析",
"workbench.settingsUnavailable": "请从 Obsidian 设置中打开本插件来调整工作台选项。",
"workbench.profileSaved": "配置已保存",
"workbench.viewReset": "视图已重置",
"workbench.infoInserted": "模型信息已插入",
"workbench.infoCopied": "模型信息已复制",
"workbench.templateInserted": "模板已插入",
"workbench.templateCopied": "模板已复制",
"workbench.mobileHint": "移动端提示:需要操作模型时点“交互”,继续阅读笔记时切回“滚动”。",
"workbench.mobileHintInteractive": "当前为交互模式。需要继续滚动笔记时,请切回“滚动”。",
"directView.mobileHint": "移动端提示:使用下方工具栏里的“交互”按钮,在模型操作和笔记滚动之间切换。",
"directWorkbench.modelLoadInterrupted": "模型加载被新请求中断。",
"directWorkbench.backendLabel": "后端",
"directWorkbench.routeLabel": "路由",
"directWorkbench.performanceLabel": "性能",
"directWorkbench.partCandidatesLabel": "候选零件",
"directWorkbench.knowledgeTitle": "知识",
"directWorkbench.registeredTitle": "已注册零件匹配",
"directWorkbench.registeredLoading": "检查中...",
"directWorkbench.registeredCount": "{count} 个匹配",
"directWorkbench.registeredEmpty": "暂无跨模型零件匹配",
"directWorkbench.registeredUnavailable": "暂无零件证据",
"directWorkbench.registeredOpen": "打开",
"directWorkbench.registeredOpenNote": "笔记",
"directWorkbench.registeredOpenModel": "模型",
"directWorkbench.registeredSourceModel": "来自 {model}",
"directWorkbench.registeredTargetPartNote": "打开匹配零件笔记",
"directWorkbench.registeredTargetSourceModel": "打开来源模型",
"directWorkbench.registeredTargetUnavailable": "暂无可打开目标",
"workbench.fileNotFound": "未找到文件:{path}",
"annotation.selectColor": "选择颜色 {color}",
"annotation.sectionEmpty": "该段内容为空。",
"modal.selectModel": "选择一个 3D 模型...",
"main.commandImportModel": "导入 3D 模型",
"main.commandGenerateNote": "生成知识笔记",
"main.commandOpenKnowledgeIndex": "打开知识索引",
"main.commandClearConversionCache": "清除转换缓存",
"main.commandCheckConverters": "检查转换器",
"main.commandCopyDiagnostics": "复制诊断报告",
"main.converterDiagnosticsMobileUnavailable": "转换器诊断仅支持桌面端。在 iOS、iPadOS 和 Android 上,直读格式仍可加载。",
"main.diagnosticsCopied": "AI Model Workbench 诊断报告已复制到剪贴板。",
"main.diagnosticsCopyFailed": "无法复制诊断报告,已改为创建一份脱敏诊断笔记。",
// 内联代码块与加载
"codeBlock.noModelPathOrConfig": "未指定模型路径或配置。",
"codeBlock.jsonParseError": "JSON 解析错误:{error}",
"codeBlock.jsonParseLine": "(第 {line} 行)",
"codeBlock.noModelsInConfig": "配置中未指定模型。",
"codeBlock.unsupportedFormat": "不支持的格式:{ext}。支持:{formats}",
"codeBlock.splatDisabled": "当前打包版本暂未启用 SPLAT 预览。后续会优先恢复本地-only .splat.spz/.sog 需要本地打包解码器后再评估。",
"codeBlock.noConfigSpecified": "未指定配置。",
"codeBlock.noModelsSpecified": "未指定模型。",
"codeBlock.mobileHint": "移动端提示:需要操作模型时点“交互”,继续阅读笔记时切回“滚动”。",
"codeBlock.renderingGrid": "正在渲染网格...",
"codeBlock.composeRequiresSections": "“compose” 预设需要提供 “sections” 数组。",
"codeBlock.composeNoValidSections": "Compose没有有效的分段。",
"codeBlock.unknownPreset": "未知预设:“{preset}”。可用compare、showcase、explode、timeline、compose",
"codeBlock.presetRequiresModels": "预设 “{preset}” 需要 {min}-{max} 个模型,当前为 {count} 个。",
"codeBlock.gridFailed": "网格渲染失败:{reason}",
"livePreview.mobileHint": "移动端提示:需要拖动模型时切到“交互”,继续阅读时切回“滚动”。",
"loading.default": "加载中...",
"loading.preparingModel": "正在准备模型...",
"loading.loadingModel": "正在加载模型...",
};
import type { TranslationKey } from "./en";
export const zhCN: Record<TranslationKey, string> = {
// 区块标题
"settings.title": "AI 3D 模型工作台",
"settings.folders": "文件夹",
"settings.behavior": "行为",
"settings.converters": "转换器",
"settings.converterMenu": "模型转换器",
"settings.converterMenu.desc": "默认收起。仅在你需要手动启用某条本地转换路线时再展开。",
"settings.environmentInspector": "环境检查器",
"settings.environmentInspector.desc": "默认收起。仅在需要配置命令路径或手动执行环境检查时再展开。",
"settings.paths": "转换器路径",
"settings.diagnostics": "转换器命令诊断",
"settings.performance": "性能与显示",
"settings.mobileSupport": "移动端支持",
"settings.knowledgeGeneration": "知识生成",
// 文件夹
"settings.sourceModelFolder": "源模型文件夹",
"settings.sourceModelFolder.desc": "存放源 3D 模型的库文件夹。",
"settings.reportFolder": "报告文件夹",
"settings.reportFolder.desc": "保存生成的知识笔记的库文件夹。",
"settings.partFolder": "部件笔记文件夹",
"settings.partFolder.desc": "保存生成的部件笔记草稿的库文件夹。",
"settings.snapshotFolder": "快照文件夹",
"settings.snapshotFolder.desc": "保存导出快照的库文件夹。",
// 行为
"settings.autoGenerateKnowledgeNotes": "自动生成知识笔记",
"settings.autoGenerateKnowledgeNotes.desc": "预留给后续自动化流程。当前请通过命令或工作台按钮手动生成知识笔记。",
"settings.annotationPreviewMode": "标注预览模式",
"settings.annotationPreviewMode.desc": "选择标注绑定笔记在悬浮预览和编辑器中的显示方式。",
"settings.annotationPreviewMode.plainText": "纯文本",
"settings.annotationPreviewMode.markdown": "Markdown",
"settings.annotationDisplayMode": "标注显示模式",
"settings.annotationDisplayMode.desc": "选择模型上书签标注的显示方式。",
"settings.annotationDisplayMode.snippet": "完整片段",
"settings.annotationDisplayMode.surface": "单个标签面",
"settings.annotationDisplayMode.dot": "单个圆点",
"settings.previewRendererRollout": "预览兼容模式",
"settings.previewRendererRollout.desc": "控制单模型预览GLB、GLTF、STL、PLY、OBJ中 Three.js 渲染路径的启用范围。只要出现 pin 投影、遮挡、编辑态 pin、快照或工具栏行为回退就切回“兼容优先”。workbench 和 3dgrid 不受这个设置影响。",
"settings.previewRendererRollout.babylonSafe": "兼容优先",
"settings.previewRendererRollout.readonly": "仅阅读场景",
"settings.previewRendererRollout.direct": "阅读 + 文件视图(推荐)",
"settings.useThreeRenderer": "使用 Three.js 渲染器",
"settings.useThreeRenderer.desc": "在 Three.js更快、更轻量和 Babylon.js完全兼容之间切换单模型预览渲染器。Three.js 支持 GLB/GLTF/STL/PLY/OBJ。工作台和 3dgrid 始终使用 Babylon.js。",
"settings.experimentalThreeWorkbench": "实验性 Three 工作台",
"settings.experimentalThreeWorkbench.desc": "仅对直读 GLB/GLTF 文件尝试使用 Three.js 工作台路径。加载失败时,文件视图会自动回退到 Babylon.js。",
"settings.autoRotateDefault": "默认自动旋转",
"settings.autoRotateDefault.desc": "启动 3D 预览时默认开启自动旋转。",
"settings.snapshotNaming": "快照命名",
"settings.snapshotNaming.desc": "导出快照文件的命名方式。",
"settings.snapshotNaming.modelName": "模型名 + 时间戳",
"settings.snapshotNaming.timestamp": "仅时间戳",
"settings.logLevel": "日志级别",
"settings.logLevel.desc": "控制插件在开发者控制台中的日志详细程度。",
"settings.language": "语言",
"settings.language.desc": "插件设置界面的显示语言。立即生效。",
"settings.analysisMode": "AI 草稿模式",
"settings.analysisMode.desc": "控制知识笔记生成保持本地,还是额外请求经过裁剪的远程草稿。当前客户端会阻止原始模型上传。",
"settings.analysisMode.local": "仅本地证据",
"settings.analysisMode.hybrid": "本地证据 + 远程草稿",
"settings.analysisMode.remote": "基于证据的远程草稿",
"settings.serviceBaseUrl": "草稿服务 URL",
"settings.serviceBaseUrl.desc": "可选的草稿服务基础地址,服务需接收 POST /draft-note。留空时所有草稿输入都保留在本地。",
"settings.sendGeometrySummaryToRemote": "发送几何摘要",
"settings.sendGeometrySummaryToRemote.desc": "允许把经过裁剪的网格数量、包围盒、部件候选、标注坐标和最近部件关联加入远程草稿输入。",
"settings.sendPreviewImagesToRemote": "发送预览图引用",
"settings.sendPreviewImagesToRemote.desc": "允许在远程草稿输入中列出生成的预览图路径。当前客户端不会上传图片字节。",
"settings.sendRawModelToRemote": "发送原始模型文件",
"settings.sendRawModelToRemote.desc": "预留给未来显式上传支持。若手动开启,远程草稿请求会被阻止,不会上传模型。",
// 转换器
"settings.enableCad": "启用 CAD 转换器 (STEP/IGES/BREP)",
"settings.enableCad.desc": "启用 STEP/IGES/BREP 格式的 CAD 转换路线,通过 Python CadQuery (OpenCASCADE)。需要pip install cadquery trimesh",
"settings.enableObj2gltf": "启用 obj2gltf 转换器(实验性)",
"settings.enableObj2gltf.desc": "默认使用 OBJ 直接加载。仅在需要本地标准化 GLB 输出时启用。",
"settings.preferObj2gltf": "OBJ 优先使用 obj2gltf",
"settings.preferObj2gltf.desc": "默认关闭。仅在需要标准化 GLB 输出或直接 OBJ 加载效果不佳时开启。",
"settings.enableFbx2gltf": "启用 FBX2glTF 转换器",
"settings.enableFbx2gltf.desc": "启用 FBX 文件通过 FBX2glTF 转换。需要本地安装 FBX2glTF 二进制文件。",
"settings.enableMesh": "启用网格转换器 (3MF/DAE)",
"settings.enableMesh.desc": "启用 3MF 和 DAE (Collada) 格式的转换路线,通过 Python trimesh。需要安装 Python 和 trimesh (pip install trimesh numpy networkx pycollada)。",
"settings.enableSldprt": "启用 SLDPRT 转换器 (SolidWorks)",
"settings.enableSldprt.desc": "启用 SolidWorks .sldprt 文件通过 FreeCAD 转换。需要安装 FreeCAD (https://www.freecad.org/downloads.php)。",
"settings.mobileSupport.desc": "在 iOS、iPadOS 和 Android 上GLB、GLTF、STL、OBJ、PLY 这类直读格式可用。本地转换器设置和命令诊断仍仅支持桌面端。",
// 转换器路径
"settings.pythonCmd": "Python 命令路径CAD 用)",
"settings.pythonCmd.desc": "可选的 Python 命令路径,用于 CAD 转换。Windows 通常用 pymacOS 和 Linux 通常用 python3。设置后覆盖自动发现和 AI3D_FREECAD_CMD。",
"settings.freecadCmd": "FreeCAD 命令路径SLDPRT 用)",
"settings.freecadCmd.desc": "可选的 FreeCAD 命令路径,用于 SolidWorks 文件转换。Windows 通常用 FreeCADCmd.exemacOS 通常用 FreeCADCmdLinux 通常用 freecadcmd。设置后覆盖自动发现和 AI3D_FREECADCMD。",
"settings.obj2gltfCmd": "obj2gltf 命令路径",
"settings.obj2gltfCmd.desc": "可选的 obj2gltf 命令路径。Windows 通常用 obj2gltf.cmdmacOS 和 Linux 通常用 obj2gltf。设置后覆盖自动发现和 AI3D_OBJ2GLTF_CMD。",
"settings.fbx2gltfCmd": "FBX2glTF 命令路径",
"settings.fbx2gltfCmd.desc": "可选的 FBX2glTF 命令路径。Windows 通常用 FBX2glTF.exemacOS 和 Linux 通常用 FBX2glTF。设置后覆盖自动发现和 AI3D_FBX2GLTF_CMD。",
"settings.assimpCmd": "Python 命令路径3MF/DAE 用)",
"settings.assimpCmd.desc": "可选的 Python 命令路径,用于 3MF 和 DAE 转换。Windows 通常用 pymacOS 和 Linux 通常用 python3。设置后覆盖自动发现和 AI3D_ASSIMP_CMD。",
// 诊断
"settings.diagnostics.desc": "显示插件当前实际使用的可执行文件路径,并为 Python 环境和转换器命令执行轻量自检。",
"settings.diagnostics.idle": "环境检查默认关闭。点击“立即检查”后才会执行。",
"settings.diagnostics.checkNow": "立即检查",
"settings.diagnostics.checking": "检查中...",
"settings.diagnostics.refreshed": "AI 3D 转换器命令诊断已刷新。",
"settings.diagnostics.checkingAvailability": "正在检查转换器命令可用性...",
"settings.diagnostics.available": "可用",
"settings.diagnostics.notFound": "未找到",
"settings.diagnostics.sourceLabel": "来源",
"settings.diagnostics.commandLabel": "命令",
"settings.diagnostics.resolvedPathLabel": "解析路径",
"settings.diagnostics.selfCheckLabel": "自检",
"settings.diagnostics.selfCheckOk": "通过",
"settings.diagnostics.selfCheckFailed": "失败",
"settings.diagnostics.cadPythonCheck": "Python 包cadquery、trimesh",
"settings.diagnostics.meshPythonCheck": "Python 包trimesh、numpy、networkx、collada",
"settings.diagnostics.freecadCmdCheck": "FreeCADCmd 启动探测",
"settings.diagnostics.obj2gltfCheck": "obj2gltf 启动探测",
"settings.diagnostics.fbx2gltfCheck": "FBX2glTF 启动探测",
// 性能
"settings.canvasHeight": "默认画布高度",
"settings.canvasHeight.desc": "内联 3D 预览的默认高度像素。范围200800。",
"settings.autoRotateSpeed": "自动旋转速度",
"settings.autoRotateSpeed.desc": "启用自动旋转时的旋转速度。范围0.12.0。",
"settings.renderQuality": "渲染质量",
"settings.renderQuality.desc": "更高质量使用更多 GPU 资源。影响抗锯齿和分辨率。",
"settings.renderScale": "渲染缩放",
"settings.renderScale.desc": "渲染分辨率倍数。1.0 = 原始0.5 = 一半2.0 = 双倍超采样。范围0.252.0。",
// 模型加载提示
"modelLoad.warningTitle": "暂时无法预览模型",
"modelLoad.warningMessage": "{ext} 文件需要先在插件设置中启用 {converterName} 转换器,才能加载。",
"modelLoad.warningHint": "请先在插件设置中启用对应转换器,然后重新加载当前文件。",
"modelLoad.mobileWarningMessage": "{ext} 文件需要本地转换工具,但这些工具在 iOS、iPadOS 和 Android 上不可用。",
"modelLoad.mobileWarningHint": "请在桌面端打开此文件,或先将它转换为 GLB、GLTF、OBJ、STL 或 PLY。",
"modelLoad.errorTitle": "无法显示这个模型",
"modelLoad.errorMessage": "加载失败:{reason}",
"modelLoad.errorHint": "请检查文件格式,或打开开发者控制台查看详细信息。",
// 标题 pin 徽标
"headingPin.showSingle": "显示关联标注",
"headingPin.showMultiple": "显示关联标注",
"headingPin.linkedTo": "关联到:{models}",
// 工具栏
"helper.resetViewLabel": "重置视图",
"helper.resetViewDone": "已重置",
"helper.copyModelInfoLabel": "复制模型信息为 Markdown",
"helper.copySelectedPartInfoLabel": "复制选中部件信息",
"helper.noSelectedPart": "请先点击一个部件",
"helper.copied": "已复制",
"helper.failed": "失败",
"helper.toggleWireframeLabel": "切换线框显示",
"helper.wireframeOn": "线框",
"helper.wireframeOff": "实体",
"helper.toggleAxesLabel": "切换方向坐标轴",
"helper.axesOn": "坐标轴已开启",
"helper.axesOff": "坐标轴已关闭",
"helper.toggleBoundingBoxLabel": "切换包围盒",
"helper.boundingBoxOn": "包围盒已开启",
"helper.boundingBoxOff": "包围盒已关闭",
"helper.toggleFocusSelectionLabel": "聚焦选中部件",
"helper.focusSelectionOn": "聚焦模式已开启",
"helper.focusSelectionOff": "聚焦模式已关闭",
"helper.toggleDisassemblyLabel": "切换分解模式",
"helper.disassemblyOn": "分解模式已开启",
"helper.disassemblyOff": "分解模式已关闭",
"helper.resetPartsLabel": "重置分解部件",
"helper.partsReset": "部件已重置",
"helper.changeResolutionLabel": "切换分辨率",
"helper.resolutionValue": "分辨率:{value}",
"helper.toggleAnimationLabel": "播放或暂停动画",
"helper.playing": "播放中",
"helper.paused": "已暂停",
"helper.toggleMeasurementLabel": "切换距离测量",
"helper.measurementOn": "测量已开启",
"helper.measurementOff": "测量已关闭",
"helper.clearMeasurementsLabel": "清除测量",
"helper.measurementsCleared": "已清除",
"helper.calibrateLabel": "校准测量比例",
"helper.calibrateTitle": "测量校准",
"helper.calibrateCurrent": "当前尺寸:",
"helper.calibrateReal": "真实尺寸:",
"helper.calibrateLock": "锁定比例",
"helper.calibrateApply": "应用",
"helper.calibrateReset": "重置",
"helper.calibrated": "比例已应用",
"helper.calibrateResetDone": "比例已重置",
"helper.calibrateOpen": "校准面板已打开",
"helper.calibrateClose": "校准面板已关闭",
"helper.removePreviewLabel": "移除预览",
"helper.copySnapshotLabel": "复制快照",
"helper.saveSnapshotLabel": "保存快照到仓库",
"helper.saved": "已保存",
"helper.downloadSnapshotLabel": "下载快照",
"helper.downloaded": "已下载",
"helper.toggleAnnotationLabel": "切换标注模式",
"helper.toggleAnnotationsVisibilityLabel": "显示或隐藏标注",
"helper.annotateOn": "标注模式已开启",
"helper.annotateOff": "标注模式已关闭",
"helper.annotationsVisible": "标注已显示",
"helper.annotationsHidden": "标注已隐藏",
"helper.enableInteractionLabel": "启用触控交互",
"helper.disableInteractionLabel": "切回滚动模式",
"helper.interactionOn": "模型交互已开启",
"helper.interactionOff": "滚动模式已开启",
"helper.showMoreActionsLabel": "显示更多操作",
"helper.hideMoreActionsLabel": "收起额外操作",
"helper.moreActionsShown": "已展开更多操作",
"helper.moreActionsHidden": "已收起额外操作",
"helper.interactAction": "交互",
"helper.scrollAction": "滚动",
// 工作台与视图
"workbench.emptyTitle": "暂无模型",
"workbench.emptyText": "使用“导入 3D 模型”命令加载 GLB、GLTF、STL、OBJ 或 PLY 文件。",
"workbench.modelTitle": "3D 模型",
"workbench.studioTitle": "AI 模型工作台",
"workbench.studioTagline": "检查、标注,并把 3D 资产整理成双链笔记。",
"workbench.navLabel": "工作台分区",
"workbench.navGallery": "画廊",
"workbench.navLibrary": "资料库",
"workbench.navNotebooks": "笔记本",
"workbench.navSettings": "设置",
"workbench.sourcesTitle": "模型来源",
"workbench.layersTitle": "审阅层",
"workbench.viewModeTitle": "视图模式",
"workbench.modeMesh": "网格视图",
"workbench.modeFocus": "聚焦选区",
"workbench.modeMeshShort": "网格",
"workbench.modeFocusShort": "聚焦",
"workbench.previewViewsTitle": "预览视图",
"workbench.connectionsTitle": "知识连接",
"workbench.currentModelLabel": "当前模型",
"workbench.noReportYet": "还没有报告笔记",
"workbench.noIndexYet": "还没有知识索引。请先生成知识笔记。",
"workbench.noModelLoaded": "尚未加载模型",
"workbench.disassemblyTitle": "分解",
"workbench.explodeLabel": "爆炸",
"workbench.summaryTitle": "摘要",
"workbench.meshesLabel": "网格",
"workbench.splatsLabel": "点云",
"workbench.trianglesLabel": "三角形",
"workbench.verticesLabel": "顶点",
"workbench.materialsLabel": "材质",
"workbench.boundingSizeLabel": "包围盒",
"workbench.centerLabel": "中心",
"workbench.selectedPartTitle": "当前选中部件",
"workbench.partMeshLabel": "网格",
"workbench.noSelectedPart": "点击模型中的部件后会显示详细信息。",
"workbench.tagsTitle": "标签",
"workbench.noTagsYet": "还没有标签",
"workbench.addTagPlaceholder": "添加标签...",
"workbench.addTagAction": "添加",
"workbench.annotationsTitle": "标注",
"workbench.exitAnnotate": "退出标注",
"workbench.annotate": "标注",
"workbench.annotateHintActive": "点击模型添加标签 · 按 Esc 退出",
"workbench.annotateHintActiveMobile": "点按模型添加标签。需要继续阅读时切回“滚动”。",
"workbench.pinCount": "{count} 个标注",
"workbench.editAction": "编辑",
"workbench.deleteAction": "删除",
"workbench.resetViewAction": "重置视图",
"workbench.insertInfoAction": "插入信息",
"workbench.insertGalleryAction": "插入 Gallery",
"workbench.insertCompareAction": "插入对比",
"workbench.playAction": "播放",
"workbench.pauseAction": "暂停",
"workbench.saveProfileAction": "保存配置",
"workbench.generateNoteAction": "生成笔记",
"workbench.openNoteAction": "打开笔记",
"workbench.openIndexAction": "打开索引",
"workbench.recordTitle": "标本卡",
"workbench.recordSubtitle": "当前资产档案",
"workbench.notesTitle": "分析札记",
"workbench.whereTitle": "关联位置",
"workbench.noteReady": "关联笔记已就绪",
"workbench.indexReady": "知识索引已就绪",
"workbench.notePending": "关联笔记待生成",
"workbench.analysisLabel": "分析",
"workbench.settingsUnavailable": "请从 Obsidian 设置中打开本插件来调整工作台选项。",
"workbench.profileSaved": "配置已保存",
"workbench.viewReset": "视图已重置",
"workbench.infoInserted": "模型信息已插入",
"workbench.infoCopied": "模型信息已复制",
"workbench.templateInserted": "模板已插入",
"workbench.templateCopied": "模板已复制",
"workbench.mobileHint": "移动端提示:需要操作模型时点“交互”,继续阅读笔记时切回“滚动”。",
"workbench.mobileHintInteractive": "当前为交互模式。需要继续滚动笔记时,请切回“滚动”。",
"directView.mobileHint": "移动端提示:使用下方工具栏里的“交互”按钮,在模型操作和笔记滚动之间切换。",
"directWorkbench.modelLoadInterrupted": "模型加载被新请求中断。",
"directWorkbench.backendLabel": "后端",
"directWorkbench.routeLabel": "路由",
"directWorkbench.performanceLabel": "性能",
"directWorkbench.partCandidatesLabel": "候选零件",
"directWorkbench.knowledgeTitle": "知识",
"directWorkbench.registeredTitle": "已注册零件匹配",
"directWorkbench.registeredLoading": "检查中...",
"directWorkbench.registeredCount": "{count} 个匹配",
"directWorkbench.registeredEmpty": "暂无跨模型零件匹配",
"directWorkbench.registeredUnavailable": "暂无零件证据",
"directWorkbench.registeredOpen": "打开",
"directWorkbench.registeredOpenNote": "笔记",
"directWorkbench.registeredOpenModel": "模型",
"directWorkbench.registeredSourceModel": "来自 {model}",
"directWorkbench.registeredTargetPartNote": "打开匹配零件笔记",
"directWorkbench.registeredTargetSourceModel": "打开来源模型",
"directWorkbench.registeredTargetUnavailable": "暂无可打开目标",
"workbench.fileNotFound": "未找到文件:{path}",
"annotation.selectColor": "选择颜色 {color}",
"annotation.sectionEmpty": "该段内容为空。",
"modal.selectModel": "选择一个 3D 模型...",
"main.commandImportModel": "导入 3D 模型",
"main.commandGenerateNote": "生成知识笔记",
"main.commandOpenKnowledgeIndex": "打开知识索引",
"main.commandClearConversionCache": "清除转换缓存",
"main.commandCheckConverters": "检查转换器",
"main.commandCopyDiagnostics": "复制诊断报告",
"main.converterDiagnosticsMobileUnavailable": "转换器诊断仅支持桌面端。在 iOS、iPadOS 和 Android 上,直读格式仍可加载。",
"main.diagnosticsCopied": "AI Model Workbench 诊断报告已复制到剪贴板。",
"main.diagnosticsCopyFailed": "无法复制诊断报告,已改为创建一份脱敏诊断笔记。",
// 内联代码块与加载
"codeBlock.noModelPathOrConfig": "未指定模型路径或配置。",
"codeBlock.jsonParseError": "JSON 解析错误:{error}",
"codeBlock.jsonParseLine": "(第 {line} 行)",
"codeBlock.noModelsInConfig": "配置中未指定模型。",
"codeBlock.unsupportedFormat": "不支持的格式:{ext}。支持:{formats}",
"codeBlock.splatDisabled": "当前打包版本暂未启用 SPLAT 预览。后续会优先恢复本地-only .splat.spz/.sog 需要本地打包解码器后再评估。",
"codeBlock.noConfigSpecified": "未指定配置。",
"codeBlock.noModelsSpecified": "未指定模型。",
"codeBlock.mobileHint": "移动端提示:需要操作模型时点“交互”,继续阅读笔记时切回“滚动”。",
"codeBlock.renderingGrid": "正在渲染网格...",
"codeBlock.composeRequiresSections": "“compose” 预设需要提供 “sections” 数组。",
"codeBlock.composeNoValidSections": "Compose没有有效的分段。",
"codeBlock.unknownPreset": "未知预设:“{preset}”。可用compare、showcase、explode、timeline、compose",
"codeBlock.presetRequiresModels": "预设 “{preset}” 需要 {min}-{max} 个模型,当前为 {count} 个。",
"codeBlock.gridFailed": "网格渲染失败:{reason}",
"livePreview.mobileHint": "移动端提示:需要拖动模型时切到“交互”,继续阅读时切回“滚动”。",
"loading.default": "加载中...",
"loading.preparingModel": "正在准备模型...",
"loading.loadingModel": "正在加载模型...",
};

View file

@ -13,12 +13,14 @@ export class ConversionTimeoutError extends Error {
}
}
function withTimeout<T>(promise: Promise<T>, ms: number, context: Record<string, unknown>): Promise<T> {
function withTimeout<T>(promise: Promise<T>, ms: number, _context: Record<string, unknown>): Promise<T> {
const setTimer = typeof activeWindow !== "undefined" ? activeWindow.setTimeout.bind(activeWindow) : setTimeout;
const clearTimer = typeof activeWindow !== "undefined" ? activeWindow.clearTimeout.bind(activeWindow) : clearTimeout;
const timeout = new Promise<never>((_, reject) => {
const id = setTimeout(() => {
const id = setTimer(() => {
reject(new ConversionTimeoutError(`Conversion did not complete within ${ms}ms`));
}, ms);
promise.then(() => clearTimeout(id)).catch(() => clearTimeout(id));
promise.then(() => clearTimer(id)).catch(() => clearTimer(id));
});
return Promise.race([promise, timeout]);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,6 @@ import {
CanvasTexture,
Color,
DirectionalLight,
Float32BufferAttribute,
GridHelper,
HemisphereLight,
Light,
@ -1912,7 +1911,7 @@ export class ThreeModelPreview implements WorkbenchPreview {
}
private createMeasurementLabelSprite(text: string, position: Vector3, scale: number): Sprite {
const canvas = document.createElement("canvas");
const canvas = activeDocument.createEl("canvas");
const ctx = canvas.getContext("2d")!;
canvas.width = 512;
canvas.height = 128;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -608,15 +608,15 @@ export function createHelperButtons(
// Calibration panel
const calibratePanel = parentEl.createDiv({ cls: "ai3d-calibrate-panel is-hidden" });
const calibrateTitle = calibratePanel.createEl("div", { cls: "ai3d-calibrate-title", text: t("helper.calibrateTitle") });
calibratePanel.createDiv({ cls: "ai3d-calibrate-title", text: t("helper.calibrateTitle") });
const boundsRow = calibratePanel.createDiv({ cls: "ai3d-calibrate-row" });
boundsRow.createEl("span", { cls: "ai3d-calibrate-label", text: t("helper.calibrateCurrent") });
const boundsX = boundsRow.createEl("span", { cls: "ai3d-calibrate-readonly" });
const boundsY = boundsRow.createEl("span", { cls: "ai3d-calibrate-readonly" });
const boundsZ = boundsRow.createEl("span", { cls: "ai3d-calibrate-readonly" });
boundsRow.createSpan({ cls: "ai3d-calibrate-label", text: t("helper.calibrateCurrent") });
const boundsX = boundsRow.createSpan({ cls: "ai3d-calibrate-readonly" });
const boundsY = boundsRow.createSpan({ cls: "ai3d-calibrate-readonly" });
const boundsZ = boundsRow.createSpan({ cls: "ai3d-calibrate-readonly" });
const realRow = calibratePanel.createDiv({ cls: "ai3d-calibrate-row" });
realRow.createEl("span", { cls: "ai3d-calibrate-label", text: t("helper.calibrateReal") });
realRow.createSpan({ cls: "ai3d-calibrate-label", text: t("helper.calibrateReal") });
const inputX = realRow.createEl("input", { cls: "ai3d-calibrate-input", attr: { type: "number", step: "any", placeholder: "X" } });
const inputY = realRow.createEl("input", { cls: "ai3d-calibrate-input", attr: { type: "number", step: "any", placeholder: "Y" } });
const inputZ = realRow.createEl("input", { cls: "ai3d-calibrate-input", attr: { type: "number", step: "any", placeholder: "Z" } });

View file

@ -1,27 +1,27 @@
{
"compilerOptions": {
"baseUrl": ".",
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "node",
"allowJs": false,
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"isolatedModules": true,
"skipLibCheck": true,
"inlineSourceMap": true,
"inlineSources": true,
"types": [
"node"
],
"lib": [
"DOM",
"ES2018"
]
},
{
"compilerOptions": {
"baseUrl": ".",
"target": "ES2018",
"module": "ESNext",
"moduleResolution": "node",
"allowJs": false,
"strict": true,
"strictNullChecks": true,
"noImplicitAny": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"isolatedModules": true,
"skipLibCheck": true,
"inlineSourceMap": true,
"inlineSources": true,
"types": [
"node"
],
"lib": [
"DOM",
"ES2018"
]
},
"include": [
"src/**/*.ts",
"scripts/**/*.ts"