Skip to content

Commit bb7be85

Browse files
Merge branch 'fix/renderer-view-continuity' into feature/sparkle-updates
# Conflicts: # docs/releasing.md
2 parents a2cc2a7 + f70d2ad commit bb7be85

206 files changed

Lines changed: 1439 additions & 609 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/blob-size-allowlist.txt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,9 @@ plugins/burette-agent/preview-web/molstar.js
1414
plugins/burette-agent/preview-web/openchemlib/openchemlib.js
1515
plugins/burette-agent/preview-web/rdkit-conformer/Burette_rdkit_conformer.wasm
1616
plugins/burette-agent/browser-shell-dist/assets/Burette_rdkit_conformer-BA7plZBF.wasm
17-
plugins/burette-agent/browser-shell-dist/assets/RDKit_minimal-tnscgqxm.wasm
18-
plugins/burette-agent/browser-shell-dist/assets/dist-ByPD0_Hs.js
19-
plugins/burette-agent/browser-shell-dist/assets/index.modern-BmjV2ZLw.js
20-
plugins/burette-agent/browser-shell-dist/assets/index.modern-CT0VIV_p.js
2117
plugins/burette-agent/browser-shell-dist/assets/indigo-ketcher-1.43.0-uUo-NEHL.wasm
2218
plugins/burette-agent/browser-shell-dist/assets/plotly-basic.min-BGGwveDV.js
2319
plugins/burette-agent/browser-shell-dist/assets/three.module-B9xciExR.js
24-
plugins/burette-agent/browser-shell-dist/assets/index.modern-610bH81i.js
2520
plugins/burette-agent/browser-shell-dist/assets/index.modern-DN6_6mNQ.js
2621
plugins/burette-agent/browser-shell-dist/index.js
2722
tests/test-ui-shell-contract.mjs
@@ -42,7 +37,6 @@ plugins/burette-agent/browser-shell-dist/assets/resources-D5ymtJwZ.json
4237
plugins/burette-agent/browser-shell-dist/assets/pdf.worker.min-BGUT02Us.mjs
4338
plugins/burette-agent/browser-shell-dist/assets/openchemlib-BteEtxM3.js
4439
plugins/burette-agent/browser-shell-dist/assets/PptxViewJS.es-CWh08j7b.js
45-
plugins/burette-agent/browser-shell-dist/assets/markdown-greenfield-content-DzW3sAaS.js
4640
plugins/burette-agent/browser-shell-dist/assets/markdown-greenfield-document.worker-qen7HUVU.js
4741
plugins/burette-agent/browser-shell-dist/assets/chunk-KEIR6QF5-CUuuYsZ_.js
4842
plugins/burette-agent/browser-shell-dist/assets/cluster-fingerprint.worker-Q1HfNbxv.js
@@ -62,3 +56,7 @@ apps/burette-public-plugin/public/demo-library/Quantum/base-pair-dens.cube
6256
apps/burette-public-plugin/public/demo-library/Quantum/base-pair-grad.cube
6357
apps/burette-public-plugin/public/demo-library/Quantum/caffeine_dens.cube
6458
apps/burette-public-plugin/public/demo-library/Quantum/caffeine_homo.cube
59+
60+
# Regenerated bundled Markdown renderer for the Story panel.
61+
plugins/burette-agent/browser-shell-dist/assets/dist-DJBUnT_G.js
62+
plugins/burette-agent/browser-shell-dist/assets/markdown-greenfield-content-C4fTLC7O.js

Burette.xcodeproj/project.pbxproj

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@
450450
GENERATE_INFOPLIST_FILE = NO;
451451
INFOPLIST_FILE = PreviewExtension/Info.plist;
452452
LD_RUNPATH_SEARCH_PATHS = ("$(inherited)", "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", );
453-
MARKETING_VERSION = 2.3.20;
453+
MARKETING_VERSION = 2.3.21;
454454
PRODUCT_BUNDLE_IDENTIFIER = com.local.BuretteV10.Preview;
455455
PRODUCT_NAME = "$(TARGET_NAME)";
456456
SKIP_INSTALL = YES;
@@ -475,7 +475,7 @@
475475
GENERATE_INFOPLIST_FILE = NO;
476476
INFOPLIST_FILE = PreviewExtension/Info.plist;
477477
LD_RUNPATH_SEARCH_PATHS = ("$(inherited)", "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", );
478-
MARKETING_VERSION = 2.3.20;
478+
MARKETING_VERSION = 2.3.21;
479479
PRODUCT_BUNDLE_IDENTIFIER = com.local.BuretteV10.Preview;
480480
PRODUCT_NAME = "$(TARGET_NAME)";
481481
SKIP_INSTALL = YES;
@@ -500,7 +500,7 @@
500500
GENERATE_INFOPLIST_FILE = NO;
501501
INFOPLIST_FILE = PreviewExtension/ThumbnailInfo.plist;
502502
LD_RUNPATH_SEARCH_PATHS = ("$(inherited)", "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", );
503-
MARKETING_VERSION = 2.3.20;
503+
MARKETING_VERSION = 2.3.21;
504504
PRODUCT_BUNDLE_IDENTIFIER = com.local.BuretteV10.Thumbnail;
505505
PRODUCT_NAME = "$(TARGET_NAME)";
506506
SKIP_INSTALL = YES;
@@ -525,7 +525,7 @@
525525
GENERATE_INFOPLIST_FILE = NO;
526526
INFOPLIST_FILE = PreviewExtension/ThumbnailInfo.plist;
527527
LD_RUNPATH_SEARCH_PATHS = ("$(inherited)", "@executable_path/../Frameworks", "@executable_path/../../../../Frameworks", );
528-
MARKETING_VERSION = 2.3.20;
528+
MARKETING_VERSION = 2.3.21;
529529
PRODUCT_BUNDLE_IDENTIFIER = com.local.BuretteV10.Thumbnail;
530530
PRODUCT_NAME = "$(TARGET_NAME)";
531531
SKIP_INSTALL = YES;
@@ -546,7 +546,7 @@
546546
GENERATE_INFOPLIST_FILE = NO;
547547
INFOPLIST_FILE = ios/BuretteMobile/Info.plist;
548548
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
549-
MARKETING_VERSION = 2.3.20;
549+
MARKETING_VERSION = 2.3.21;
550550
PRODUCT_BUNDLE_IDENTIFIER = com.local.BuretteV10.Mobile;
551551
PRODUCT_NAME = "$(TARGET_NAME)";
552552
SDKROOT = iphoneos;
@@ -569,7 +569,7 @@
569569
GENERATE_INFOPLIST_FILE = NO;
570570
INFOPLIST_FILE = ios/BuretteMobile/Info.plist;
571571
IPHONEOS_DEPLOYMENT_TARGET = 17.0;
572-
MARKETING_VERSION = 2.3.20;
572+
MARKETING_VERSION = 2.3.21;
573573
PRODUCT_BUNDLE_IDENTIFIER = com.local.BuretteV10.Mobile;
574574
PRODUCT_NAME = "$(TARGET_NAME)";
575575
SDKROOT = iphoneos;

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

PreviewExtension/Web/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
<script src="./molstar-preset-preview-controller.js"></script>
4343
<script src="./superposition-panel.js"></script>
4444
<script src="./molecule-preview-interactions.js"></script>
45+
<script src="./renderer-view-state.js"></script>
4546
<script src="./color-picker.js"></script>
4647
<script src="./sequence-panel.js"></script>
4748
<script src="./scene-file-actions.js"></script>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Presentation state only: source coordinates and rendered SVG data stay untouched.
2+
(function () {
3+
'use strict';
4+
const storageKey = 'burette.renderer-views.v1';
5+
let memory = {};
6+
function readAll() {
7+
try {
8+
const text = window.sessionStorage.getItem(storageKey);
9+
if (text && text.length < 256000) memory = JSON.parse(text);
10+
} catch (_) {}
11+
return memory && typeof memory === 'object' && !Array.isArray(memory) ? memory : {};
12+
}
13+
function camera(value) {
14+
if (!value || !['position', 'target', 'up'].every(key =>
15+
Array.isArray(value[key]) && value[key].length === 3 && value[key].every(Number.isFinite))) return null;
16+
if (!(value.radius > 0) || !Number.isFinite(value.radius)) return null;
17+
const result = { position: value.position.slice(), target: value.target.slice(), up: value.up.slice(), radius: value.radius };
18+
for (const key of ['fov', 'radiusMax', 'fog', 'clipFar', 'minNear', 'minFar']) {
19+
if (Number.isFinite(value[key])) result[key] = value[key];
20+
}
21+
if (value.mode === 'perspective' || value.mode === 'orthographic') result.mode = value.mode;
22+
return result;
23+
}
24+
function xyz(value) {
25+
if (!value || !['scale', 'x', 'y'].every(key => Number.isFinite(value[key]))) return null;
26+
if (value.scale < 0.05 || value.scale > 8) return null;
27+
const result = { scale: value.scale, x: value.x, y: value.y };
28+
if (value.item && ['left', 'top', 'width', 'height', 'rotation'].every(key => Number.isFinite(value.item[key]))) {
29+
result.item = Object.fromEntries(['left', 'top', 'width', 'height', 'rotation'].map(key => [key, value.item[key]]));
30+
}
31+
return result;
32+
}
33+
function read(id, initial) {
34+
if (typeof id !== 'string' || !id || id.length > 2048) return {};
35+
const values = readAll();
36+
let value = Object.hasOwn(values, id) ? values[id] : null;
37+
if (!value && typeof initial === 'string' && initial.length <= 8192) {
38+
try { value = JSON.parse(initial); } catch (_) {}
39+
if (value) { save(id, value); }
40+
}
41+
return value ? { camera: camera(value.camera), xyz: xyz(value.xyz) } : {};
42+
}
43+
function save(id, patch) {
44+
if (typeof id !== 'string' || !id || id.length > 2048) return;
45+
const values = readAll();
46+
const previous = read(id);
47+
delete values[id];
48+
values[id] = {
49+
camera: camera(patch.camera) || previous.camera || null,
50+
xyz: xyz(patch.xyz) || previous.xyz || null
51+
};
52+
for (const key of Object.keys(values).slice(0, -32)) delete values[key];
53+
memory = values;
54+
try { window.sessionStorage.setItem(storageKey, JSON.stringify(values)); } catch (_) {}
55+
}
56+
window.BuretteRendererViewState = { read, save };
57+
})();

PreviewExtension/Web/viewer-runtime.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5345,6 +5345,10 @@ body:not(.burette-mobile-host) .buret-molecule-context-menu .buret-picking-level
53455345
background: var(--buret-molstar-hover-background);
53465346
}
53475347

5348+
/* Compact viewports keep the scene clear; the host Story tab owns the prose. */
5349+
@media (max-width: 1000px), (max-height: 650px) {
5350+
body .msp-plugin .msp-snapshot-description-wrapper { display: none !important; }
5351+
}
53485352
/* Snapshot navigation is owned by Burette scene controls. */
53495353
.msp-state-snapshot-viewport-controls {
53505354
display: none !important;

PreviewExtension/Web/viewer.js

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,12 +2538,34 @@
25382538
return values.every(number => Number.isFinite(number) && number > 0) ? values : null;
25392539
}
25402540

2541+
let externalArtifactViewSnapshot = null;
2542+
2543+
function saveRendererViewState() {
2544+
const config = activeConfig || window.BuretteConfig || {};
2545+
const patch = config.renderer === 'xyzrender-external'
2546+
? { xyz: externalArtifactViewSnapshot?.() }
2547+
: { camera: captureMolstarCameraSnapshot(activeViewer) };
2548+
window.BuretteRendererViewState?.save(config.documentId, patch);
2549+
const viewState = window.BuretteRendererViewState?.read(config.documentId);
2550+
postHostMessage({ type: 'rendererViewStateChanged', viewState });
2551+
return viewState;
2552+
}
2553+
window.addEventListener('pagehide', saveRendererViewState);
2554+
let rendererViewSaveTimer;
2555+
const scheduleRendererViewSave = () => {
2556+
clearTimeout(rendererViewSaveTimer);
2557+
rendererViewSaveTimer = setTimeout(saveRendererViewState, 250);
2558+
};
2559+
window.addEventListener('pointerup', scheduleRendererViewSave);
2560+
window.addEventListener('wheel', scheduleRendererViewSave, { passive: true });
2561+
25412562
function requestRendererSwitch(renderer) {
2563+
const viewState = saveRendererViewState();
25422564
const value = normalizeRenderer(renderer);
25432565
if (requestBrowserDevRendererSwitch(value)) return;
25442566
const orientationRef = value === 'xyzrender-external' ? captureCurrentXyzrenderOrientationRef() : null;
2545-
const activeModel = value === 'xyzrender-external' ? activeTrajectoryFrameIndexForRendererSwitch() : null;
2546-
const payload = { type: 'setRenderer', value };
2567+
const activeModel = activeTrajectoryFrameIndexForRendererSwitch();
2568+
const payload = { type: 'setRenderer', value, viewState };
25472569
if (orientationRef) {
25482570
payload.orientationRef = orientationRef.text;
25492571
payload.orientationAtomCount = orientationRef.atomCount;
@@ -13544,9 +13566,10 @@ SOFTWARE.
1354413566
const stage = root.querySelector('.buret-external-artifact-stage');
1354513567
if (!stage) return;
1354613568

13547-
let scale = 1;
13548-
let translateX = 0;
13549-
let translateY = 0;
13569+
const savedView = window.BuretteRendererViewState?.read(activeConfig?.documentId, activeConfig?.rendererViewState).xyz;
13570+
let scale = savedView?.scale ?? 1;
13571+
let translateX = savedView?.x ?? 0;
13572+
let translateY = savedView?.y ?? 0;
1355013573
let dragPointerId = null;
1355113574
let dragClientX = 0;
1355213575
let dragClientY = 0;
@@ -13663,6 +13686,19 @@ SOFTWARE.
1366313686
};
1366413687
installExternalArtifactBaseItemInteractions(root, () => scale);
1366513688
const sheetCleanup = installExternalArtifactSheet(root, stage, toStagePoint, () => scale);
13689+
const baseItem = root.querySelector('.buret-xyzrender-sheet-item-base');
13690+
if (baseItem && savedView?.item) {
13691+
for (const key of ['left', 'top', 'width', 'height']) baseItem.style[key] = `${savedView.item[key]}px`;
13692+
setSheetItemRotation(baseItem, savedView.item.rotation);
13693+
}
13694+
externalArtifactViewSnapshot = () => ({
13695+
scale, x: translateX, y: translateY,
13696+
item: baseItem ? {
13697+
left: baseItem.offsetLeft, top: baseItem.offsetTop,
13698+
width: baseItem.offsetWidth, height: baseItem.offsetHeight,
13699+
rotation: Number(baseItem.dataset.rotation || 0)
13700+
} : null
13701+
});
1366613702

1366713703
root.addEventListener('wheel', onWheel, { passive: false });
1366813704
root.addEventListener('pointerdown', onPointerDown);
@@ -13674,6 +13710,8 @@ SOFTWARE.
1367413710
root.addEventListener('gesturechange', onGestureChange, { passive: false });
1367513711
apply();
1367613712
externalArtifactInteractionsCleanup = () => {
13713+
saveRendererViewState();
13714+
externalArtifactViewSnapshot = null;
1367713715
root.removeEventListener('wheel', onWheel);
1367813716
root.removeEventListener('pointerdown', onPointerDown);
1367913717
root.removeEventListener('pointermove', onPointerMove);
@@ -26104,7 +26142,11 @@ ${config.label || 'structure'} (${formatLabel}${size ? `, ${size}` : ''})`);
2610426142
} catch (error) {
2610526143
debug('Configured Mol* preset failed: ' + (error?.message || String(error)));
2610626144
}
26107-
if (!hasMolstarContextFocus(config)) {
26145+
const savedCamera = window.BuretteRendererViewState?.read(config.documentId, config.rendererViewState).camera;
26146+
if (savedCamera && !hasMolstarContextFocus(config) && prepared.kind !== 'mvs') {
26147+
molstarStructureFocusSerial += 1;
26148+
restoreMolstarCameraSnapshotNow(viewer, savedCamera);
26149+
} else if (!hasMolstarContextFocus(config)) {
2610826150
scheduleMolstarStructureFocus(viewer, { reason: 'initial-load', durationMs: 120 });
2610926151
}
2611026152
{

apps/desktop/src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/desktop/src-tauri/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "burette"
3-
version = "2.3.20"
3+
version = "2.3.21"
44
description = "Tauri/Rust shell for local molecular previews"
55
authors = ["Burette"]
66
edition = "2021"

apps/desktop/src-tauri/src/commands/documents.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3786,6 +3786,7 @@ mod tests {
37863786
},
37873787
preferences,
37883788
Some(super::ViewerReloadOptions {
3789+
renderer_view_state: None,
37893790
xyzrender_orientation_ref: None,
37903791
xyzrender_preset: None,
37913792
xyzrender_controls: None,

0 commit comments

Comments
 (0)