diff --git a/CHANGELOG.md b/CHANGELOG.md
index 12bdbf4..bd287f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,23 @@ All notable changes to the **VS Code Aster** extension will be documented in thi
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [1.7.0] - 2026-04-16
+
+New viewer toolbar with bounding box, wireframe, and screenshot tools.
+
+### Added
+- Top toolbar in the mesh viewer with three new tools:
+ - **Bounding box**: toggleable wireframe cube with colored axes (X red, Y green, Z blue), corner dots, a "0" origin marker, and dimension labels anchored in 3D
+ - **Wireframe mode**: toggle between solid surface and wireframe rendering to inspect mesh density
+ - **Screenshot**: left click saves the 3D view as PNG next to the source file and copies to clipboard; right click captures the full viewer including the sidebar
+- Toolbar button tooltips using the same inline hover pattern as the rest of the UI
+- Toolbar tab in the viewer help popup documenting the three new tools
+- Updated README with diagnostics, terminal reuse, direct `.med` opening, and toolbar features
+
+### Fixed
+- Popup z-order: help and settings popups no longer render behind the sidebar
+- Sidebar tooltip z-order: filter/clear tooltips no longer hidden behind the top toolbar
+
## [1.6.1] - 2026-04-15
Standalone mesh visualization: click any `.med` file to open the viewer directly, even without a `.comm`/`.export` pair.
diff --git a/CITATION.cff b/CITATION.cff
index 7950d6d..55948ee 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -1,4 +1,4 @@
-cff-version: 1.6.1
+cff-version: 1.7.0
title: VS Code Aster
message: >-
If you use this software, please cite it using the
diff --git a/README.md b/README.md
index 76bf4ba..8d55815 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@

-
+
@@ -135,7 +135,11 @@ There are two ways to open the form :
1. Open a `.export` file.
2. Click on the "play" icon `Run with code_aster` in the top-right corner of the file.
-It will open a terminal and execute the following command : `cave run [file].export`.
+It will open a terminal and execute the following command : `cave run [file].export`. Subsequent runs reuse the same terminal.
+
+**Diagnostics**
+
+Warnings (``), errors (``, ``), Python tracebacks, and fatal errors from code_aster automatically appear in the VS Code **Problems panel** after a run — no `F mess` entry required in the `.export` file. Diagnostics are attached to the originating `.comm` line when possible and cleared between runs.
**Personnalize alias to run code-aster**
@@ -182,21 +186,24 @@ The visualizer is an integrated 3D viewer that lets you display and explore your
It’s powered by **VTK.js**, and supports both mesh visualization and node-based groups.
-#### Opening the visualizer
+
-The visualizer is very easy to open :
+#### Opening the visualizer
-1. Open a `.comm` file.
-2. Click on the "eye" icon `Open visualizer` in the top-right corner of the file.
+There are two ways to open the visualizer :
-The visualizer is now open !
+- **From a `.comm` file** : click on the "eye" icon `Open visualizer` in the top-right corner of the file.
+- **From a `.med` file** : click any `.med`, `.mmed`, or `.rmed` file in the explorer — it opens directly in the viewer, no `.comm` file needed. Files with non-standard MED extensions (e.g. `.71`) are auto-detected and can be registered in one click.
#### Features
- Load geometry files (`.med`) directly into the viewer
- Highlight face and node groups using the sidebar
- Highlight groups quickly by selecting their names from your command file (`.comm`)
-- Control the camera with by rotating or panning it
+- Control the camera by rotating or panning it
+- **Bounding box** : toggle a wireframe cube with colored axes (X red, Y green, Z blue), corner dots, and dimension labels to quickly read the characteristic size of the structure
+- **Wireframe mode** : switch between solid surface and wireframe rendering to inspect mesh density
+- **Screenshot** : save the current 3D view as a PNG file next to your mesh and copy it to the clipboard
#### Usage tips
@@ -211,6 +218,9 @@ The visualizer is now open !
- Hold `Shift` + `Left click` and move your mouse to pan the camera
- Use the `Mouse wheel` to zoom in and out
- Click on the `X`, `Y`, and `Z` buttons at the bottom of the sidebar to quickly align the camera along an axis
+- Toolbar :
+ - The top toolbar provides quick access to the bounding box, wireframe, and screenshot features
+ - Right-click the screenshot button to capture the full viewer including the sidebar
- File management :
- Mesh files (`.*med` files) are converted to `.obj` files, which are stored in a hidden folder called `.visu_data/` in your workspace
diff --git a/ROADMAP.md b/ROADMAP.md
index fbfaa89..3308232 100644
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -4,7 +4,7 @@
The extension aims to reduce friction between modeling, validation, execution, and analysis by bringing **code_aster** native workflows into the editor.
-## Current Capabilities (v1.6.1)
+## Current Capabilities (v1.7.0)
- `.export` file generator
- 3D mesh viewer
diff --git a/media/images/viewer-screenshot.png b/media/images/viewer-screenshot.png
new file mode 100644
index 0000000..95999ef
Binary files /dev/null and b/media/images/viewer-screenshot.png differ
diff --git a/package-lock.json b/package-lock.json
index 1b1a5ff..72ffd93 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "vs-code-aster",
- "version": "1.6.1",
+ "version": "1.7.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "vs-code-aster",
- "version": "1.6.1",
+ "version": "1.7.0",
"license": "GPL-3.0",
"dependencies": {
"@tailwindcss/cli": "^4.1.17",
@@ -23,6 +23,7 @@
"@vscode/test-electron": "^2.5.2",
"esbuild": "^0.25.5",
"eslint": "^9.25.1",
+ "html-to-image": "^1.11.13",
"husky": "^9.1.7",
"npm-run-all": "^4.1.5",
"prettier": "^3.8.1",
@@ -3433,6 +3434,13 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/html-to-image": {
+ "version": "1.11.13",
+ "resolved": "https://registry.npmjs.org/html-to-image/-/html-to-image-1.11.13.tgz",
+ "integrity": "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/http-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
diff --git a/package.json b/package.json
index deb8c15..1c82f2c 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "vs-code-aster",
"displayName": "VS Code Aster",
- "version": "1.6.1",
+ "version": "1.7.0",
"description": "VS Code extension for code_aster",
"publisher": "simvia",
"license": "GPL-3.0",
@@ -138,9 +138,15 @@
"viewType": "vs-code-aster.medViewer",
"displayName": "MED Mesh Viewer",
"selector": [
- { "filenamePattern": "*.med" },
- { "filenamePattern": "*.mmed" },
- { "filenamePattern": "*.rmed" }
+ {
+ "filenamePattern": "*.med"
+ },
+ {
+ "filenamePattern": "*.mmed"
+ },
+ {
+ "filenamePattern": "*.rmed"
+ }
],
"priority": "default"
}
@@ -274,6 +280,18 @@
"default": true,
"markdownDescription": "Show the orientation axes widget in the bottom-right corner of the viewer."
},
+ "vs-code-aster.viewer.showBoundingBox": {
+ "order": 17,
+ "type": "boolean",
+ "default": false,
+ "markdownDescription": "Show a bounding box with X/Y/Z tick marks and values around the loaded meshes in the viewer."
+ },
+ "vs-code-aster.viewer.showWireframe": {
+ "order": 18,
+ "type": "boolean",
+ "default": false,
+ "markdownDescription": "Render meshes in wireframe mode instead of solid surfaces."
+ },
"vs-code-aster.enableTelemetry": {
"order": 100,
"type": "boolean",
@@ -306,6 +324,7 @@
"@vscode/test-electron": "^2.5.2",
"esbuild": "^0.25.5",
"eslint": "^9.25.1",
+ "html-to-image": "^1.11.13",
"husky": "^9.1.7",
"npm-run-all": "^4.1.5",
"prettier": "^3.8.1",
diff --git a/src/MedEditorProvider.ts b/src/MedEditorProvider.ts
index 4f072d5..fe026db 100644
--- a/src/MedEditorProvider.ts
+++ b/src/MedEditorProvider.ts
@@ -76,6 +76,7 @@ export class MedEditorProvider implements vscode.CustomReadonlyEditorProvider {
this.activeViewers.delete(medPath);
diff --git a/src/VisuManager.ts b/src/VisuManager.ts
index 94a0cba..9aad1b9 100644
--- a/src/VisuManager.ts
+++ b/src/VisuManager.ts
@@ -128,6 +128,7 @@ export class VisuManager {
commName
);
+ visu.sourceDir = path.dirname(commUri.fsPath);
this.views.set(key, { commUri, objUris, visu });
// Send telemetry once per opening of this .comm (non-blocking).
diff --git a/src/WebviewVisu.ts b/src/WebviewVisu.ts
index 4322eb0..b7c28fe 100644
--- a/src/WebviewVisu.ts
+++ b/src/WebviewVisu.ts
@@ -14,6 +14,7 @@ export class WebviewVisu implements vscode.Disposable {
private readyReceived = false;
private deferredInit?: { fileContexts: string[]; objFilenames: string[] };
+ public sourceDir?: string;
public get webview(): vscode.Webview {
return this.panel.webview;
@@ -119,6 +120,8 @@ export class WebviewVisu implements vscode.Disposable {
'edgeMode',
'groupTransparency',
'showOrientationWidget',
+ 'showBoundingBox',
+ 'showWireframe',
];
for (const key of settingKeys) {
if (e.settings[key] !== undefined) {
@@ -126,6 +129,15 @@ export class WebviewVisu implements vscode.Disposable {
}
}
break;
+ case 'saveScreenshot': {
+ if (this.sourceDir) {
+ const base64 = (e.dataUrl as string).replace(/^data:image\/png;base64,/, '');
+ const buffer = Buffer.from(base64, 'base64');
+ const filePath = path.join(this.sourceDir, e.filename as string);
+ fs.writeFileSync(filePath, buffer);
+ }
+ break;
+ }
case 'debugPanel':
// Log debug messages from the webview
console.log('[WebviewVisu] Message received from webview:', e.text);
@@ -178,6 +190,8 @@ export class WebviewVisu implements vscode.Disposable {
edgeMode: config.get('viewer.edgeMode', 'threshold'),
groupTransparency: config.get('viewer.groupTransparency', 0.2),
showOrientationWidget: config.get('viewer.showOrientationWidget', true),
+ showBoundingBox: config.get('viewer.showBoundingBox', false),
+ showWireframe: config.get('viewer.showWireframe', false),
};
this.panel.webview.postMessage({
type: 'init',
diff --git a/webviews/viewer/index.html b/webviews/viewer/index.html
index 318a9bc..8782a87 100644
--- a/webviews/viewer/index.html
+++ b/webviews/viewer/index.html
@@ -6,7 +6,7 @@
MeshViewer
-
+
diff --git a/webviews/viewer/src/components/layout/App.svelte b/webviews/viewer/src/components/layout/App.svelte
index e689b8d..3d03e61 100644
--- a/webviews/viewer/src/components/layout/App.svelte
+++ b/webviews/viewer/src/components/layout/App.svelte
@@ -2,7 +2,9 @@
import { groupHierarchy } from '../../lib/state';
import Sidebar from './Sidebar.svelte';
import TopActions from './TopActions.svelte';
+ import TopToolbar from './TopToolbar.svelte';
import ZoomWidget from '../viewer/ZoomWidget.svelte';
+ import BoundingBoxLabels from '../viewer/BoundingBoxLabels.svelte';
import Popup from '../popups/Popup.svelte';
import HelpPopup from '../popups/HelpPopup.svelte';
import SettingsPopup from '../popups/SettingsPopup.svelte';
@@ -35,7 +37,11 @@
}}
/>
+
+
+
+
{/if}
{#if openPopup}
diff --git a/webviews/viewer/src/components/layout/Sidebar.svelte b/webviews/viewer/src/components/layout/Sidebar.svelte
index a07090e..670e236 100644
--- a/webviews/viewer/src/components/layout/Sidebar.svelte
+++ b/webviews/viewer/src/components/layout/Sidebar.svelte
@@ -13,7 +13,7 @@
});
-