@lingbi/studio 0.8.1 → 0.8.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.
- package/assets/{StabilityWorkerEntry-CXCNaUyw.js → StabilityWorkerEntry-L0_8iZmQ.js} +13327 -13205
- package/index.js +164 -67
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -33618,25 +33618,21 @@ class PlyLoader {
|
|
|
33618
33618
|
}
|
|
33619
33619
|
}
|
|
33620
33620
|
class SimulationSnapshotFactory {
|
|
33621
|
-
|
|
33621
|
+
constructor(scheduler) {
|
|
33622
|
+
this.scheduler = scheduler;
|
|
33623
|
+
}
|
|
33624
|
+
scheduler;
|
|
33625
|
+
// Allocation granularity, not a per-task limit: tasks copy until their time budget expires.
|
|
33626
|
+
static CHUNK_BYTES = 4 * 1024 * 1024;
|
|
33627
|
+
static ATTRIBUTE_CHUNK_BYTES = 256 * 1024;
|
|
33628
|
+
async create(stone, base) {
|
|
33622
33629
|
const started = performance.now();
|
|
33623
33630
|
const stoneRoot = this.root(stone);
|
|
33624
33631
|
const baseRoot = this.root(base);
|
|
33625
33632
|
stoneRoot.updateMatrixWorld(true);
|
|
33626
33633
|
if (baseRoot !== stoneRoot) baseRoot.updateMatrixWorld(true);
|
|
33627
|
-
const stoneInput = this.collect(stone);
|
|
33628
|
-
const baseInput = this.collect(base);
|
|
33629
|
-
const bounds = new Box3();
|
|
33630
|
-
const point = new Vector3();
|
|
33631
|
-
for (let index = 0; index < stoneInput.positions.length; index += 3) {
|
|
33632
|
-
bounds.expandByPoint(point.fromArray(stoneInput.positions, index));
|
|
33633
|
-
}
|
|
33634
|
-
const origin = bounds.getCenter(new Vector3()).toArray();
|
|
33635
|
-
for (const input of [stoneInput, baseInput]) {
|
|
33636
|
-
for (let index = 0; index < input.positions.length; index++) {
|
|
33637
|
-
input.positions[index] = Number(input.positions[index]) - Number(origin[index % 3]);
|
|
33638
|
-
}
|
|
33639
|
-
}
|
|
33634
|
+
const stoneInput = await this.collect(stone);
|
|
33635
|
+
const baseInput = await this.collect(base);
|
|
33640
33636
|
return {
|
|
33641
33637
|
stone: stoneInput,
|
|
33642
33638
|
base: baseInput,
|
|
@@ -33648,54 +33644,126 @@ class SimulationSnapshotFactory {
|
|
|
33648
33644
|
while (root.parent !== null) root = root.parent;
|
|
33649
33645
|
return root;
|
|
33650
33646
|
}
|
|
33651
|
-
collect(root) {
|
|
33652
|
-
const
|
|
33653
|
-
const
|
|
33654
|
-
const
|
|
33655
|
-
|
|
33656
|
-
if (
|
|
33647
|
+
async collect(root) {
|
|
33648
|
+
const result = [];
|
|
33649
|
+
const objects = [root];
|
|
33650
|
+
for (const object of objects) {
|
|
33651
|
+
const pause = this.scheduler.checkpoint();
|
|
33652
|
+
if (pause !== void 0) await pause;
|
|
33653
|
+
objects.push(...object.children);
|
|
33654
|
+
if (!(object instanceof Mesh)) continue;
|
|
33657
33655
|
const mesh = object;
|
|
33658
|
-
if (!mesh.geometry.hasAttribute("position")) {
|
|
33659
|
-
throw new Error("The model has no triangular position attribute.");
|
|
33660
|
-
}
|
|
33661
33656
|
const position = mesh.geometry.getAttribute("position");
|
|
33662
|
-
if (position.itemSize < 3) {
|
|
33657
|
+
if (!mesh.geometry.hasAttribute("position") || position.itemSize < 3) {
|
|
33663
33658
|
throw new Error("The model has no triangular position attribute.");
|
|
33664
33659
|
}
|
|
33665
|
-
const
|
|
33666
|
-
if (!Number.isFinite
|
|
33667
|
-
throw new Error("The model transform is
|
|
33668
|
-
}
|
|
33669
|
-
const
|
|
33670
|
-
|
|
33671
|
-
|
|
33672
|
-
|
|
33673
|
-
|
|
33674
|
-
|
|
33675
|
-
|
|
33676
|
-
|
|
33677
|
-
|
|
33678
|
-
|
|
33679
|
-
|
|
33680
|
-
|
|
33681
|
-
|
|
33682
|
-
|
|
33683
|
-
|
|
33684
|
-
|
|
33685
|
-
|
|
33686
|
-
|
|
33687
|
-
|
|
33688
|
-
))
|
|
33689
|
-
|
|
33690
|
-
|
|
33691
|
-
|
|
33692
|
-
offset
|
|
33693
|
-
offset
|
|
33694
|
-
offset +
|
|
33695
|
-
|
|
33660
|
+
const matrixWorld = mesh.matrixWorld.toArray();
|
|
33661
|
+
if (!matrixWorld.every(Number.isFinite)) {
|
|
33662
|
+
throw new Error("The model transform is nonfinite.");
|
|
33663
|
+
}
|
|
33664
|
+
const positions = await this.copyPositions(position);
|
|
33665
|
+
const index = mesh.geometry.index;
|
|
33666
|
+
const indices = index === null ? null : await this.copyIndices(index);
|
|
33667
|
+
result.push({ positions, indices, vertexCount: position.count, matrixWorld });
|
|
33668
|
+
}
|
|
33669
|
+
return result;
|
|
33670
|
+
}
|
|
33671
|
+
async copyPositions(attribute) {
|
|
33672
|
+
const result = [];
|
|
33673
|
+
const source = attribute.array;
|
|
33674
|
+
const packed = !("isInterleavedBufferAttribute" in attribute) && !attribute.normalized && attribute.itemSize === 3 && (source instanceof Float32Array || source instanceof Float64Array);
|
|
33675
|
+
const vertexChunk = Math.floor(
|
|
33676
|
+
(packed ? SimulationSnapshotFactory.CHUNK_BYTES : SimulationSnapshotFactory.ATTRIBUTE_CHUNK_BYTES) / 24
|
|
33677
|
+
);
|
|
33678
|
+
for (let start = 0; start < attribute.count; start += vertexChunk) {
|
|
33679
|
+
const pause = this.scheduler.checkpoint();
|
|
33680
|
+
if (pause !== void 0) await pause;
|
|
33681
|
+
const end = Math.min(attribute.count, start + vertexChunk);
|
|
33682
|
+
if (packed) {
|
|
33683
|
+
result.push(source.slice(start * 3, end * 3));
|
|
33684
|
+
} else {
|
|
33685
|
+
const values = new Float64Array((end - start) * 3);
|
|
33686
|
+
for (let index = start; index < end; index++) {
|
|
33687
|
+
const offset = (index - start) * 3;
|
|
33688
|
+
values[offset] = attribute.getX(index);
|
|
33689
|
+
values[offset + 1] = attribute.getY(index);
|
|
33690
|
+
values[offset + 2] = attribute.getZ(index);
|
|
33691
|
+
}
|
|
33692
|
+
result.push(values);
|
|
33693
|
+
}
|
|
33694
|
+
}
|
|
33695
|
+
return result;
|
|
33696
|
+
}
|
|
33697
|
+
async copyIndices(attribute) {
|
|
33698
|
+
const result = [];
|
|
33699
|
+
const source = attribute.array;
|
|
33700
|
+
const packed = attribute.itemSize === 1 && !attribute.normalized && (source instanceof Uint16Array || source instanceof Uint32Array);
|
|
33701
|
+
const indexChunk = (packed ? SimulationSnapshotFactory.CHUNK_BYTES : SimulationSnapshotFactory.ATTRIBUTE_CHUNK_BYTES) / 8;
|
|
33702
|
+
for (let start = 0; start < attribute.count; start += indexChunk) {
|
|
33703
|
+
const pause = this.scheduler.checkpoint();
|
|
33704
|
+
if (pause !== void 0) await pause;
|
|
33705
|
+
const end = Math.min(attribute.count, start + indexChunk);
|
|
33706
|
+
if (packed) result.push(source.slice(start, end));
|
|
33707
|
+
else {
|
|
33708
|
+
const values = new Float64Array(end - start);
|
|
33709
|
+
for (let index = start; index < end; index++) {
|
|
33710
|
+
values[index - start] = attribute.getX(index);
|
|
33711
|
+
}
|
|
33712
|
+
result.push(values);
|
|
33696
33713
|
}
|
|
33714
|
+
}
|
|
33715
|
+
return result;
|
|
33716
|
+
}
|
|
33717
|
+
}
|
|
33718
|
+
class SimulationTaskScheduler {
|
|
33719
|
+
constructor(signal, started) {
|
|
33720
|
+
this.signal = signal;
|
|
33721
|
+
this.started = started;
|
|
33722
|
+
}
|
|
33723
|
+
signal;
|
|
33724
|
+
started;
|
|
33725
|
+
sliceStarted = performance.now();
|
|
33726
|
+
async waitForPaint() {
|
|
33727
|
+
await this.wait(true);
|
|
33728
|
+
this.checkActive();
|
|
33729
|
+
this.sliceStarted = performance.now();
|
|
33730
|
+
}
|
|
33731
|
+
checkpoint() {
|
|
33732
|
+
this.checkActive();
|
|
33733
|
+
if (performance.now() - this.sliceStarted < 4) return void 0;
|
|
33734
|
+
return this.yieldTask();
|
|
33735
|
+
}
|
|
33736
|
+
async yieldTask() {
|
|
33737
|
+
await this.wait(false);
|
|
33738
|
+
this.checkActive();
|
|
33739
|
+
this.sliceStarted = performance.now();
|
|
33740
|
+
}
|
|
33741
|
+
checkActive() {
|
|
33742
|
+
this.signal.throwIfAborted();
|
|
33743
|
+
if (performance.now() - this.started >= 3e4) {
|
|
33744
|
+
throw new Error("Simulation timed out during snapshot capture.");
|
|
33745
|
+
}
|
|
33746
|
+
}
|
|
33747
|
+
wait(paint) {
|
|
33748
|
+
this.checkActive();
|
|
33749
|
+
return new Promise((resolve) => {
|
|
33750
|
+
let frame;
|
|
33751
|
+
let task;
|
|
33752
|
+
const finish = () => {
|
|
33753
|
+
if (frame !== void 0) cancelAnimationFrame(frame);
|
|
33754
|
+
clearTimeout(task);
|
|
33755
|
+
this.signal.removeEventListener("abort", finish);
|
|
33756
|
+
resolve();
|
|
33757
|
+
};
|
|
33758
|
+
this.signal.addEventListener("abort", finish, { once: true });
|
|
33759
|
+
if (paint) {
|
|
33760
|
+
frame = requestAnimationFrame(() => {
|
|
33761
|
+
clearTimeout(task);
|
|
33762
|
+
task = setTimeout(finish, 0);
|
|
33763
|
+
});
|
|
33764
|
+
}
|
|
33765
|
+
task = setTimeout(finish, paint ? 100 : 0);
|
|
33697
33766
|
});
|
|
33698
|
-
return { positions: Float64Array.from(positions), indices: Uint32Array.from(indices) };
|
|
33699
33767
|
}
|
|
33700
33768
|
}
|
|
33701
33769
|
class StabilityMessages {
|
|
@@ -33703,7 +33771,7 @@ class StabilityMessages {
|
|
|
33703
33771
|
if (!this.record(value) || !this.token(value["token"]) || !this.record(value["input"]))
|
|
33704
33772
|
return void 0;
|
|
33705
33773
|
const input = value["input"];
|
|
33706
|
-
if (!this.
|
|
33774
|
+
if (!this.role(input["stone"]) || !this.role(input["base"]) || !this.nonnegative(input["captureMilliseconds"]))
|
|
33707
33775
|
return void 0;
|
|
33708
33776
|
return value;
|
|
33709
33777
|
}
|
|
@@ -33736,8 +33804,20 @@ class StabilityMessages {
|
|
|
33736
33804
|
}
|
|
33737
33805
|
return value["outcome"] !== "supported" || Number(value["margin"]) > 1e-6 && Number(value["residual"]) <= 1e-7 && Number(value["contactCount"]) > 0;
|
|
33738
33806
|
}
|
|
33807
|
+
role(value) {
|
|
33808
|
+
return this.array(value) && value.every((mesh) => this.mesh(mesh));
|
|
33809
|
+
}
|
|
33810
|
+
array(value) {
|
|
33811
|
+
return Array.isArray(value);
|
|
33812
|
+
}
|
|
33739
33813
|
mesh(value) {
|
|
33740
|
-
return this.record(value) && value["positions"]
|
|
33814
|
+
return this.record(value) && Array.isArray(value["positions"]) && value["positions"].every(
|
|
33815
|
+
(chunk) => chunk instanceof Float32Array || chunk instanceof Float64Array
|
|
33816
|
+
) && (value["indices"] === null || Array.isArray(value["indices"]) && value["indices"].every(
|
|
33817
|
+
(chunk) => chunk instanceof Uint16Array || chunk instanceof Uint32Array || chunk instanceof Float64Array
|
|
33818
|
+
)) && this.nonnegative(value["vertexCount"]) && Number.isSafeInteger(value["vertexCount"]) && Array.isArray(value["matrixWorld"]) && value["matrixWorld"].length === 16 && value["matrixWorld"].every(
|
|
33819
|
+
(entry) => typeof entry === "number" && Number.isFinite(entry)
|
|
33820
|
+
);
|
|
33741
33821
|
}
|
|
33742
33822
|
record(value) {
|
|
33743
33823
|
return typeof value === "object" && value !== null;
|
|
@@ -33753,7 +33833,7 @@ class StabilityWorkerFactory {
|
|
|
33753
33833
|
create() {
|
|
33754
33834
|
return new Worker(new URL(
|
|
33755
33835
|
/* @vite-ignore */
|
|
33756
|
-
"" + new URL("assets/StabilityWorkerEntry-
|
|
33836
|
+
"" + new URL("assets/StabilityWorkerEntry-L0_8iZmQ.js", import.meta.url).href,
|
|
33757
33837
|
import.meta.url
|
|
33758
33838
|
), {
|
|
33759
33839
|
type: "module"
|
|
@@ -33802,12 +33882,16 @@ class StabilityWorkerClient {
|
|
|
33802
33882
|
this.fail("Simulation Worker message could not be read.");
|
|
33803
33883
|
});
|
|
33804
33884
|
}
|
|
33805
|
-
|
|
33806
|
-
|
|
33807
|
-
|
|
33808
|
-
|
|
33809
|
-
|
|
33810
|
-
|
|
33885
|
+
const transfer = [];
|
|
33886
|
+
for (const role of [input.stone, input.base]) {
|
|
33887
|
+
for (const mesh of role) {
|
|
33888
|
+
for (const chunk of mesh.positions) transfer.push(chunk.buffer);
|
|
33889
|
+
if (mesh.indices !== null) {
|
|
33890
|
+
for (const chunk of mesh.indices) transfer.push(chunk.buffer);
|
|
33891
|
+
}
|
|
33892
|
+
}
|
|
33893
|
+
}
|
|
33894
|
+
worker.postMessage({ token, input }, transfer);
|
|
33811
33895
|
} catch {
|
|
33812
33896
|
this.fail("Simulation Worker could not start.");
|
|
33813
33897
|
}
|
|
@@ -35826,6 +35910,7 @@ class Renderer {
|
|
|
35826
35910
|
contextLost = false;
|
|
35827
35911
|
booleanOperationInProgress = false;
|
|
35828
35912
|
simulationInProgress = false;
|
|
35913
|
+
simulationCapture;
|
|
35829
35914
|
simulationToken = 0;
|
|
35830
35915
|
simulationWorker = new StabilityWorkerClient();
|
|
35831
35916
|
booleanOperationWorkerClient;
|
|
@@ -36359,6 +36444,8 @@ class Renderer {
|
|
|
36359
36444
|
const started = performance.now();
|
|
36360
36445
|
const token = ++this.simulationToken;
|
|
36361
36446
|
const revision = this.sceneRevision;
|
|
36447
|
+
const capture = new AbortController();
|
|
36448
|
+
this.simulationCapture = capture;
|
|
36362
36449
|
this.simulationInProgress = true;
|
|
36363
36450
|
try {
|
|
36364
36451
|
this.gizmoController.end();
|
|
@@ -36387,7 +36474,13 @@ class Renderer {
|
|
|
36387
36474
|
console.info("[stone-stability]", response2);
|
|
36388
36475
|
return response2;
|
|
36389
36476
|
}
|
|
36390
|
-
const
|
|
36477
|
+
const scheduler = new SimulationTaskScheduler(capture.signal, started);
|
|
36478
|
+
await scheduler.waitForPaint();
|
|
36479
|
+
const input = await new SimulationSnapshotFactory(scheduler).create(
|
|
36480
|
+
stone.object,
|
|
36481
|
+
base.object
|
|
36482
|
+
);
|
|
36483
|
+
capture.signal.throwIfAborted();
|
|
36391
36484
|
const response = await this.simulationWorker.run(input, started);
|
|
36392
36485
|
if (token !== this.simulationToken || revision !== this.sceneRevision || !this.isDualModelSceneReady()) {
|
|
36393
36486
|
return { status: "cancelled" };
|
|
@@ -36395,11 +36488,13 @@ class Renderer {
|
|
|
36395
36488
|
console.info("[stone-stability]", response);
|
|
36396
36489
|
return response;
|
|
36397
36490
|
} catch (error2) {
|
|
36491
|
+
if (capture.signal.aborted) return { status: "cancelled" };
|
|
36398
36492
|
const reason = error2 instanceof Error ? error2.message : "Simulation failed.";
|
|
36399
36493
|
console.info("[stone-stability]", { status: "failed", reason });
|
|
36400
36494
|
return { status: "failed", reason };
|
|
36401
36495
|
} finally {
|
|
36402
36496
|
if (token === this.simulationToken) {
|
|
36497
|
+
this.simulationCapture = void 0;
|
|
36403
36498
|
this.simulationInProgress = false;
|
|
36404
36499
|
this.notifyWorkspaceState();
|
|
36405
36500
|
}
|
|
@@ -36407,6 +36502,8 @@ class Renderer {
|
|
|
36407
36502
|
}
|
|
36408
36503
|
cancelSimulation() {
|
|
36409
36504
|
const wasActive = this.simulationInProgress;
|
|
36505
|
+
this.simulationCapture?.abort();
|
|
36506
|
+
this.simulationCapture = void 0;
|
|
36410
36507
|
this.simulationToken++;
|
|
36411
36508
|
this.simulationInProgress = false;
|
|
36412
36509
|
this.simulationWorker.cancel();
|
|
@@ -39914,7 +40011,7 @@ var StoneBasePoseMode = /* @__PURE__ */ ((StoneBasePoseMode2) => {
|
|
|
39914
40011
|
StoneBasePoseMode2["PreservePose"] = "preserve-pose";
|
|
39915
40012
|
return StoneBasePoseMode2;
|
|
39916
40013
|
})(StoneBasePoseMode || {});
|
|
39917
|
-
const studioWorkspaceStyles = ".lingbi-studio-workspace {\n position: relative;\n display: block;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n.lingbi-studio-viewport {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n.lingbi-studio-viewport > canvas {\n display: block;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background: #3d3f41;\n}\n\n.lingbi-studio-boolean-operation-overlay {\n position: absolute;\n z-index: 3;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n background: rgba(17, 17, 17, 0.32);\n color: #ffffff;\n cursor: wait;\n}\n\n.lingbi-studio-boolean-operation-overlay[hidden] {\n display: none;\n}\n\n.lingbi-studio-boolean-edit-confirmation {\n position: absolute;\n z-index: 4;\n top: 50%;\n left: 50%;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n width: min(420px, calc(100% - 32px));\n padding: 24px;\n border-radius: 8px;\n background: #ffffff;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.22);\n transform: translate(-50%, -50%);\n box-sizing: border-box;\n}\n\n.lingbi-studio-boolean-edit-confirmation[hidden] {\n display: none;\n}\n\n.lingbi-studio-boolean-edit-confirmation-text {\n grid-column: 1 / -1;\n margin: 0 0 8px;\n color: #171717;\n font-size: 16px;\n font-weight: 500;\n line-height: 24px;\n text-align: center;\n}\n\n.lingbi-studio-boolean-edit-confirmation-cancel,\n.lingbi-studio-boolean-edit-confirmation-continue {\n height: 40px;\n border: 1px solid #d9d9d9;\n border-radius: 4px;\n font: inherit;\n font-size: 16px;\n font-weight: 500;\n line-height: 24px;\n cursor: pointer;\n}\n\n.lingbi-studio-boolean-edit-confirmation-cancel {\n background: #ffffff;\n color: #171717;\n}\n\n.lingbi-studio-boolean-edit-confirmation-continue {\n border-color: #f27c38;\n background: #f27c38;\n color: #ffffff;\n}\n\n.lingbi-studio-boolean-operation-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid rgba(255, 105, 0, 0.28);\n border-top-color: #ff6900;\n border-radius: 50%;\n animation: lingbi-studio-boolean-operation-spin 0.8s linear infinite;\n box-sizing: border-box;\n}\n\n.lingbi-studio-boolean-operation-status {\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n letter-spacing: 0;\n}\n\n.lingbi-studio-bottom-toolbar {\n position: absolute;\n z-index: 1;\n bottom: 36px;\n left: 50%;\n display: grid;\n align-items: center;\n grid-template-columns: minmax(0, 1fr);\n width: min(120px, calc(100% - 32px));\n height: 64px;\n padding: 8px 12px;\n transform: translateX(-50%);\n box-sizing: border-box;\n border-radius: 8px;\n background: #f4f4f4;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.14);\n}\n\n.lingbi-studio-bottom-toolbar.has-edit-control {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n width: min(480px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-inventory-control {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n width: min(240px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-edit-control.has-inventory-control {\n grid-template-columns: repeat(5, minmax(0, 1fr));\n width: min(600px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-model-control.has-inventory-control {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n width: min(360px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-model-control.has-edit-control {\n grid-template-columns: repeat(5, minmax(0, 1fr));\n width: min(600px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-model-control.has-edit-control.has-inventory-control {\n grid-template-columns: repeat(6, minmax(0, 1fr));\n width: min(720px, calc(100% - 32px));\n}\n\n.lingbi-studio-model-visibility {\n position: absolute;\n z-index: 1;\n bottom: 108px;\n left: 50%;\n display: grid;\n gap: 8px;\n width: 144px;\n padding: 12px;\n border-radius: 8px;\n background: #f4f4f4;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.14);\n transform: translateX(-240px);\n box-sizing: border-box;\n}\n\n.lingbi-studio-model-visibility[hidden] {\n display: none;\n}\n\n.lingbi-studio-model-visibility-title {\n color: #171717;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.lingbi-studio-model-visibility-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px;\n align-items: center;\n color: #171717;\n font-size: 14px;\n line-height: 20px;\n}\n\n.lingbi-studio-model-visibility-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n appearance: none;\n width: 20px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n color: #171717;\n cursor: not-allowed;\n font: inherit;\n line-height: 0;\n outline: none;\n box-sizing: border-box;\n}\n\n.lingbi-studio-model-visibility-icon {\n display: block;\n width: 18px;\n height: 18px;\n flex: 0 0 auto;\n pointer-events: none;\n}\n\n.lingbi-studio-model-visibility-button:not(:disabled) {\n cursor: pointer;\n}\n\n.lingbi-studio-model-visibility-button:disabled {\n color: #8c8c8c;\n}\n\n.lingbi-studio-model-button.is-active,\n.lingbi-studio-model-button.is-active:disabled {\n color: #ff6900;\n font-weight: 600;\n}\n\n.lingbi-studio-boolean-button,\n.lingbi-studio-simulation-button,\n.lingbi-studio-download-button,\n.lingbi-studio-inventory-button,\n.lingbi-studio-edit-button,\n.lingbi-studio-model-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n min-width: 0;\n height: 48px;\n padding: 0 8px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n color: #171717;\n cursor: not-allowed;\n font: inherit;\n font-size: 18px;\n font-weight: 500;\n line-height: 24px;\n letter-spacing: 0;\n opacity: 1;\n box-sizing: border-box;\n white-space: nowrap;\n transition:\n background-color 140ms ease,\n color 140ms ease;\n}\n\n.lingbi-studio-operation-button-wrapper {\n display: block;\n width: 100%;\n min-width: 0;\n height: 48px;\n box-sizing: border-box;\n}\n\n.lingbi-studio-operation-button-wrapper > button:disabled {\n pointer-events: none;\n}\n\n.lingbi-studio-boolean-button[hidden],\n.lingbi-studio-simulation-button[hidden],\n.lingbi-studio-download-button[hidden],\n.lingbi-studio-inventory-button[hidden],\n.lingbi-studio-edit-button[hidden],\n.lingbi-studio-model-button[hidden] {\n display: none;\n}\n\n.lingbi-studio-boolean-button:not(:disabled),\n.lingbi-studio-simulation-button:not(:disabled),\n.lingbi-studio-download-button:not(:disabled),\n.lingbi-studio-inventory-button:not(:disabled),\n.lingbi-studio-edit-button:not(:disabled),\n.lingbi-studio-model-button:not(:disabled) {\n cursor: pointer;\n}\n\n.lingbi-studio-boolean-button:disabled,\n.lingbi-studio-simulation-button:disabled,\n.lingbi-studio-download-button:disabled,\n.lingbi-studio-inventory-button:disabled,\n.lingbi-studio-edit-button:disabled,\n.lingbi-studio-model-button:disabled,\n.lingbi-studio-model-visibility-button:disabled {\n background: transparent;\n color: #8c8c8c;\n opacity: 1;\n}\n\n.lingbi-studio-edit-button.is-active,\n.lingbi-studio-edit-button.is-active:disabled,\n.lingbi-studio-model-button.is-active,\n.lingbi-studio-model-button.is-active:disabled {\n color: #ff6900;\n font-weight: 600;\n}\n\n.lingbi-studio-download-status {\n position: absolute;\n z-index: 2;\n top: 24px;\n left: 50%;\n max-width: calc(100% - 24px);\n padding: 6px 10px;\n border: 1px solid #f4b5b0;\n border-radius: 4px;\n background: #fff1f0;\n color: #b42318;\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n text-align: center;\n transform: translateX(-50%);\n box-sizing: border-box;\n}\n\n.lingbi-studio-download-status[hidden] {\n display: none;\n}\n\n.lingbi-studio-download-success {\n position: absolute;\n z-index: 2;\n top: 24px;\n left: 50%;\n max-width: calc(100% - 24px);\n padding: 8px 16px;\n border: 1px solid #86d39a;\n border-radius: 6px;\n background: #f0fff4;\n color: #176b32;\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n text-align: center;\n transform: translateX(-50%);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n box-sizing: border-box;\n}\n\n.lingbi-studio-download-success[hidden] {\n display: none;\n}\n\n.lingbi-studio-edit-status {\n position: absolute;\n z-index: 2;\n bottom: 112px;\n left: 50%;\n display: flex;\n align-items: center;\n gap: 12px;\n max-width: calc(100% - 24px);\n padding: 10px 14px;\n border: 0;\n border-radius: 8px;\n background: #e9e9e9;\n color: #171717;\n transform: translateX(-50%);\n box-sizing: border-box;\n}\n\n.lingbi-studio-edit-status[hidden] {\n display: none;\n}\n\n.lingbi-studio-edit-status-text {\n display: inline-block;\n min-width: 0;\n font-size: 20px;\n line-height: 28px;\n letter-spacing: 0;\n}\n\n.lingbi-studio-exit-button {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n height: 40px;\n padding: 0 18px;\n border: 1px solid transparent;\n border-radius: 8px;\n background: #f27c38;\n color: #ffffff;\n cursor: pointer;\n font: inherit;\n font-size: 18px;\n font-weight: 600;\n line-height: 24px;\n letter-spacing: 0;\n transition:\n background-color 140ms ease,\n color 140ms ease;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .lingbi-studio-boolean-button:not(:disabled):hover,\n .lingbi-studio-simulation-button:not(:disabled):hover,\n .lingbi-studio-download-button:not(:disabled):hover,\n .lingbi-studio-inventory-button:not(:disabled):hover,\n .lingbi-studio-edit-button:not(:disabled):hover,\n .lingbi-studio-model-button:not(:disabled):hover {\n background: #e8e8e8;\n }\n\n .lingbi-studio-edit-button:not(:disabled):hover {\n color: #f06400;\n }\n\n .lingbi-studio-model-button:not(:disabled):hover {\n color: #f06400;\n }\n\n .lingbi-studio-model-visibility-button:not(:disabled):hover {\n background: transparent;\n }\n\n .lingbi-studio-exit-button:hover {\n background: #ff8a1f;\n }\n\n .lingbi-studio-boolean-edit-confirmation-cancel:hover {\n background: #f5f5f5;\n }\n\n .lingbi-studio-boolean-edit-confirmation-continue:hover {\n background: #ff8a1f;\n }\n}\n\n.lingbi-studio-boolean-button:not(:disabled):active,\n.lingbi-studio-download-button:not(:disabled):active,\n.lingbi-studio-inventory-button:not(:disabled):active,\n.lingbi-studio-edit-button:not(:disabled):active,\n.lingbi-studio-model-button:not(:disabled):active,\n.lingbi-studio-model-visibility-button:not(:disabled):active {\n background: transparent;\n}\n\n.lingbi-studio-exit-button:active {\n background: #e66d00;\n}\n\n@keyframes lingbi-studio-boolean-operation-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .lingbi-studio-boolean-button,\n .lingbi-studio-simulation-button,\n .lingbi-studio-download-button,\n .lingbi-studio-inventory-button,\n .lingbi-studio-edit-button,\n .lingbi-studio-model-button,\n .lingbi-studio-exit-button {\n transition: none;\n }\n\n .lingbi-studio-boolean-operation-spinner {\n animation: none;\n }\n}\n\n@media (max-width: 420px) {\n .lingbi-studio-bottom-toolbar.has-edit-control {\n width: calc(100% - 16px);\n padding: 8px 4px;\n }\n\n .lingbi-studio-bottom-toolbar.has-model-control.has-edit-control {\n width: calc(100% - 16px);\n }\n\n .lingbi-studio-bottom-toolbar.has-model-control.has-edit-control.has-inventory-control {\n width: calc(100% - 16px);\n }\n\n .lingbi-studio-model-visibility {\n left: 8px;\n transform: none;\n }\n\n .lingbi-studio-boolean-button,\n .lingbi-studio-simulation-button,\n .lingbi-studio-download-button,\n .lingbi-studio-inventory-button,\n .lingbi-studio-edit-button,\n .lingbi-studio-model-button {\n padding: 0 2px;\n font-size: 16px;\n }\n\n .lingbi-studio-edit-status-text {\n font-size: 16px;\n line-height: 24px;\n }\n\n .lingbi-studio-exit-button {\n height: 36px;\n padding: 0 14px;\n font-size: 16px;\n }\n}\n\n.lingbi-studio-viewport > canvas:focus-visible,\n.lingbi-studio-boolean-button:focus-visible,\n.lingbi-studio-simulation-button:focus-visible,\n.lingbi-studio-download-button:focus-visible,\n.lingbi-studio-inventory-button:focus-visible,\n.lingbi-studio-edit-button:focus-visible,\n.lingbi-studio-model-button:focus-visible,\n.lingbi-studio-model-visibility-button:focus-visible,\n.lingbi-studio-exit-button:focus-visible,\n.lingbi-studio-boolean-edit-confirmation-cancel:focus-visible,\n.lingbi-studio-boolean-edit-confirmation-continue:focus-visible {\n outline: 2px solid #7cc0ff;\n outline-offset: 2px;\n}\n";
|
|
40014
|
+
const studioWorkspaceStyles = ".lingbi-studio-workspace {\n position: relative;\n display: block;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n.lingbi-studio-viewport {\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n}\n\n.lingbi-studio-viewport > canvas {\n display: block;\n width: 100%;\n height: 100%;\n min-width: 0;\n min-height: 0;\n overflow: hidden;\n background: #3d3f41;\n}\n\n.lingbi-studio-boolean-operation-overlay {\n position: absolute;\n z-index: 3;\n inset: 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 12px;\n background: rgba(17, 17, 17, 0.32);\n color: #ffffff;\n cursor: wait;\n}\n\n.lingbi-studio-boolean-operation-overlay[hidden] {\n display: none;\n}\n\n.lingbi-studio-boolean-edit-confirmation {\n position: absolute;\n z-index: 4;\n top: 50%;\n left: 50%;\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n width: min(420px, calc(100% - 32px));\n padding: 24px;\n border-radius: 8px;\n background: #ffffff;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.22);\n transform: translate(-50%, -50%);\n box-sizing: border-box;\n}\n\n.lingbi-studio-boolean-edit-confirmation[hidden] {\n display: none;\n}\n\n.lingbi-studio-boolean-edit-confirmation-text {\n grid-column: 1 / -1;\n margin: 0 0 8px;\n color: #171717;\n font-size: 16px;\n font-weight: 500;\n line-height: 24px;\n text-align: center;\n}\n\n.lingbi-studio-boolean-edit-confirmation-cancel,\n.lingbi-studio-boolean-edit-confirmation-continue {\n height: 40px;\n border: 1px solid #d9d9d9;\n border-radius: 4px;\n font: inherit;\n font-size: 16px;\n font-weight: 500;\n line-height: 24px;\n cursor: pointer;\n}\n\n.lingbi-studio-boolean-edit-confirmation-cancel {\n background: #ffffff;\n color: #171717;\n}\n\n.lingbi-studio-boolean-edit-confirmation-continue {\n border-color: #f27c38;\n background: #f27c38;\n color: #ffffff;\n}\n\n.lingbi-studio-boolean-operation-spinner {\n width: 32px;\n height: 32px;\n border: 3px solid rgba(255, 105, 0, 0.28);\n border-top-color: #ff6900;\n border-radius: 50%;\n animation: lingbi-studio-boolean-operation-spin 0.8s linear infinite;\n box-sizing: border-box;\n}\n\n.lingbi-studio-boolean-operation-status {\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n letter-spacing: 0;\n}\n\n.lingbi-studio-bottom-toolbar {\n position: absolute;\n z-index: 1;\n bottom: 36px;\n left: 50%;\n display: grid;\n align-items: center;\n grid-template-columns: minmax(0, 1fr);\n width: min(120px, calc(100% - 32px));\n height: 64px;\n padding: 8px 12px;\n transform: translateX(-50%);\n box-sizing: border-box;\n border-radius: 8px;\n background: #f4f4f4;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.14);\n}\n\n.lingbi-studio-bottom-toolbar.has-edit-control {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n width: min(480px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-inventory-control {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n width: min(240px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-edit-control.has-inventory-control {\n grid-template-columns: repeat(5, minmax(0, 1fr));\n width: min(600px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-model-control.has-inventory-control {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n width: min(360px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-model-control.has-edit-control {\n grid-template-columns: repeat(5, minmax(0, 1fr));\n width: min(600px, calc(100% - 32px));\n}\n\n.lingbi-studio-bottom-toolbar.has-model-control.has-edit-control.has-inventory-control {\n grid-template-columns: repeat(6, minmax(0, 1fr));\n width: min(720px, calc(100% - 32px));\n}\n\n.lingbi-studio-model-visibility {\n position: absolute;\n z-index: 1;\n bottom: 108px;\n left: 50%;\n display: grid;\n gap: 8px;\n width: 144px;\n padding: 12px;\n border-radius: 8px;\n background: #f4f4f4;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.14);\n transform: translateX(-240px);\n box-sizing: border-box;\n}\n\n.lingbi-studio-model-visibility[hidden] {\n display: none;\n}\n\n.lingbi-studio-model-visibility-title {\n color: #171717;\n font-size: 14px;\n font-weight: 600;\n line-height: 20px;\n}\n\n.lingbi-studio-model-visibility-row {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px;\n align-items: center;\n color: #171717;\n font-size: 14px;\n line-height: 20px;\n}\n\n.lingbi-studio-model-visibility-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n appearance: none;\n width: 20px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n color: #171717;\n cursor: not-allowed;\n font: inherit;\n line-height: 0;\n outline: none;\n box-sizing: border-box;\n}\n\n.lingbi-studio-model-visibility-icon {\n display: block;\n width: 18px;\n height: 18px;\n flex: 0 0 auto;\n pointer-events: none;\n}\n\n.lingbi-studio-model-visibility-button:not(:disabled) {\n cursor: pointer;\n}\n\n.lingbi-studio-model-visibility-button:disabled {\n color: #8c8c8c;\n}\n\n.lingbi-studio-model-button.is-active,\n.lingbi-studio-model-button.is-active:disabled {\n color: #ff6900;\n font-weight: 600;\n}\n\n.lingbi-studio-boolean-button,\n.lingbi-studio-simulation-button,\n.lingbi-studio-download-button,\n.lingbi-studio-inventory-button,\n.lingbi-studio-edit-button,\n.lingbi-studio-model-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n min-width: 0;\n height: 48px;\n padding: 0 8px;\n border: 0;\n border-radius: 4px;\n background: transparent;\n color: #171717;\n cursor: not-allowed;\n font: inherit;\n font-size: 18px;\n font-weight: 500;\n line-height: 24px;\n letter-spacing: 0;\n opacity: 1;\n box-sizing: border-box;\n white-space: nowrap;\n transition:\n background-color 140ms ease,\n color 140ms ease;\n}\n\n.lingbi-studio-operation-button-wrapper {\n display: block;\n width: 100%;\n min-width: 0;\n height: 48px;\n box-sizing: border-box;\n}\n\n.lingbi-studio-operation-button-wrapper > button:disabled {\n pointer-events: none;\n}\n\n.lingbi-studio-boolean-button[hidden],\n.lingbi-studio-simulation-button[hidden],\n.lingbi-studio-download-button[hidden],\n.lingbi-studio-inventory-button[hidden],\n.lingbi-studio-edit-button[hidden],\n.lingbi-studio-model-button[hidden] {\n display: none;\n}\n\n.lingbi-studio-boolean-button:not(:disabled),\n.lingbi-studio-simulation-button:not(:disabled),\n.lingbi-studio-download-button:not(:disabled),\n.lingbi-studio-inventory-button:not(:disabled),\n.lingbi-studio-edit-button:not(:disabled),\n.lingbi-studio-model-button:not(:disabled) {\n cursor: pointer;\n}\n\n.lingbi-studio-boolean-button:disabled,\n.lingbi-studio-simulation-button:disabled,\n.lingbi-studio-download-button:disabled,\n.lingbi-studio-inventory-button:disabled,\n.lingbi-studio-edit-button:disabled,\n.lingbi-studio-model-button:disabled,\n.lingbi-studio-model-visibility-button:disabled {\n background: transparent;\n color: #8c8c8c;\n opacity: 1;\n}\n\n.lingbi-studio-edit-button.is-active,\n.lingbi-studio-edit-button.is-active:disabled,\n.lingbi-studio-model-button.is-active,\n.lingbi-studio-model-button.is-active:disabled {\n color: #ff6900;\n font-weight: 600;\n}\n\n.lingbi-studio-download-status {\n position: absolute;\n z-index: 2;\n top: 24px;\n left: 50%;\n max-width: calc(100% - 24px);\n padding: 6px 10px;\n border: 1px solid #f4b5b0;\n border-radius: 4px;\n background: #fff1f0;\n color: #b42318;\n font-size: 13px;\n font-weight: 500;\n line-height: 20px;\n text-align: center;\n transform: translateX(-50%);\n box-sizing: border-box;\n}\n\n.lingbi-studio-download-status[hidden] {\n display: none;\n}\n\n.lingbi-studio-download-success {\n position: absolute;\n z-index: 2;\n top: 24px;\n left: 50%;\n max-width: calc(100% - 24px);\n padding: 8px 16px;\n border: 1px solid #86d39a;\n border-radius: 6px;\n background: #f0fff4;\n color: #176b32;\n font-size: 14px;\n font-weight: 500;\n line-height: 20px;\n text-align: center;\n transform: translateX(-50%);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n box-sizing: border-box;\n}\n\n.lingbi-studio-download-success[hidden] {\n display: none;\n}\n\n.lingbi-studio-edit-status {\n position: absolute;\n z-index: 2;\n bottom: 112px;\n left: 50%;\n display: flex;\n align-items: center;\n gap: 12px;\n max-width: calc(100% - 24px);\n padding: 10px 14px;\n border: 0;\n border-radius: 8px;\n background: #e9e9e9;\n color: #171717;\n transform: translateX(-50%);\n box-sizing: border-box;\n}\n\n.lingbi-studio-edit-status[hidden] {\n display: none;\n}\n\n.lingbi-studio-edit-status-text {\n display: inline-block;\n min-width: 0;\n font-size: 20px;\n line-height: 28px;\n letter-spacing: 0;\n}\n\n.lingbi-studio-exit-button {\n display: inline-flex;\n flex: 0 0 auto;\n align-items: center;\n justify-content: center;\n height: 40px;\n padding: 0 18px;\n border: 1px solid transparent;\n border-radius: 8px;\n background: #f27c38;\n color: #ffffff;\n cursor: pointer;\n font: inherit;\n font-size: 18px;\n font-weight: 600;\n line-height: 24px;\n letter-spacing: 0;\n transition:\n background-color 140ms ease,\n color 140ms ease;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .lingbi-studio-boolean-button:not(:disabled):hover,\n .lingbi-studio-simulation-button:not(:disabled):hover,\n .lingbi-studio-download-button:not(:disabled):hover,\n .lingbi-studio-inventory-button:not(:disabled):hover,\n .lingbi-studio-edit-button:not(:disabled):hover,\n .lingbi-studio-model-button:not(:disabled):hover {\n background: #e8e8e8;\n }\n\n .lingbi-studio-simulation-button:not(:disabled):hover,\n .lingbi-studio-download-button:not(:disabled):hover,\n .lingbi-studio-inventory-button:not(:disabled):hover,\n .lingbi-studio-edit-button:not(:disabled):hover,\n .lingbi-studio-model-button:not(:disabled):hover {\n color: #f06400;\n }\n\n .lingbi-studio-model-visibility-button:not(:disabled):hover {\n background: transparent;\n }\n\n .lingbi-studio-exit-button:hover {\n background: #ff8a1f;\n }\n\n .lingbi-studio-boolean-edit-confirmation-cancel:hover {\n background: #f5f5f5;\n }\n\n .lingbi-studio-boolean-edit-confirmation-continue:hover {\n background: #ff8a1f;\n }\n}\n\n.lingbi-studio-boolean-button:not(:disabled):active,\n.lingbi-studio-download-button:not(:disabled):active,\n.lingbi-studio-inventory-button:not(:disabled):active,\n.lingbi-studio-edit-button:not(:disabled):active,\n.lingbi-studio-model-button:not(:disabled):active,\n.lingbi-studio-model-visibility-button:not(:disabled):active {\n background: transparent;\n}\n\n.lingbi-studio-exit-button:active {\n background: #e66d00;\n}\n\n@keyframes lingbi-studio-boolean-operation-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .lingbi-studio-boolean-button,\n .lingbi-studio-simulation-button,\n .lingbi-studio-download-button,\n .lingbi-studio-inventory-button,\n .lingbi-studio-edit-button,\n .lingbi-studio-model-button,\n .lingbi-studio-exit-button {\n transition: none;\n }\n\n .lingbi-studio-boolean-operation-spinner {\n animation: none;\n }\n}\n\n@media (max-width: 420px) {\n .lingbi-studio-bottom-toolbar.has-edit-control {\n width: calc(100% - 16px);\n padding: 8px 4px;\n }\n\n .lingbi-studio-bottom-toolbar.has-model-control.has-edit-control {\n width: calc(100% - 16px);\n }\n\n .lingbi-studio-bottom-toolbar.has-model-control.has-edit-control.has-inventory-control {\n width: calc(100% - 16px);\n }\n\n .lingbi-studio-model-visibility {\n left: 8px;\n transform: none;\n }\n\n .lingbi-studio-boolean-button,\n .lingbi-studio-simulation-button,\n .lingbi-studio-download-button,\n .lingbi-studio-inventory-button,\n .lingbi-studio-edit-button,\n .lingbi-studio-model-button {\n padding: 0 2px;\n font-size: 16px;\n }\n\n .lingbi-studio-edit-status-text {\n font-size: 16px;\n line-height: 24px;\n }\n\n .lingbi-studio-exit-button {\n height: 36px;\n padding: 0 14px;\n font-size: 16px;\n }\n}\n\n.lingbi-studio-viewport > canvas:focus-visible,\n.lingbi-studio-boolean-button:focus-visible,\n.lingbi-studio-simulation-button:focus-visible,\n.lingbi-studio-download-button:focus-visible,\n.lingbi-studio-inventory-button:focus-visible,\n.lingbi-studio-edit-button:focus-visible,\n.lingbi-studio-model-button:focus-visible,\n.lingbi-studio-model-visibility-button:focus-visible,\n.lingbi-studio-exit-button:focus-visible,\n.lingbi-studio-boolean-edit-confirmation-cancel:focus-visible,\n.lingbi-studio-boolean-edit-confirmation-continue:focus-visible {\n outline: 2px solid #7cc0ff;\n outline-offset: 2px;\n}\n";
|
|
39918
40015
|
class StudioWorkspace {
|
|
39919
40016
|
canvas;
|
|
39920
40017
|
static SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|