Crystal Studio Web runs an interactive crystal viewer in the browser and uses a small Python API to parse uploaded sources. The frontend uses Vite, Three.js and jsPDF; the API uses FastAPI. Publish the contents of this folder as a separate repository.
The deployed workspace is available at Crystal Studio Web. Its Python API runs on Render Free, and the source is hosted in BrahimELMokhtari/crystal-studio-web. The published viewer already includes the API address; uploads use that service automatically.
See VALIDATION.md for tested features and export measurements. The supplied archive also includes a production frontend build in frontend/dist.
Use Undo and Redo in the main toolbar to reverse or reapply edits, including atom deletion, manual connections, sizes, display controls and camera changes. Keyboard shortcuts are Ctrl/Command+Z, Ctrl/Command+Shift+Z and Ctrl+Y. Text fields keep their normal typing shortcuts; workspace shortcuts are inactive inside dialogs or during calculations/exports. History keeps up to 50 snapshots within a 32 MiB budget in this tab, and resets on refresh. Download a project to keep work beyond the session.
The Quick guide beside Undo/Redo explains manual cells, atom editing, mouse connections, shortcuts, transparent figures and project downloads.
Full unit cell makes every displayed boundary image selectable in the scene and Atoms table. The table identifies the original site and image shift, with the image’s actual fractional/Cartesian coordinates. Image selection preserves the stored periodic basis; measurements and manual connections use the selected physical positions.
Left-click toggles atoms without a three-atom limit. Left-drag draws a selection box by default. Ctrl/Command + drag adds to the selection and Alt + drag removes from it; boxes include centers behind foreground atoms. Change Drag: select to Drag: rotate for ordinary rotation; Shift + drag still selects in rotate mode. The wheel zooms and right-drag pans. Select all atoms, or Ctrl/Command+A while focused in the workspace, selects every displayed position. Use exactly two or three positions for distance/angle measurements.
Click empty space to clear the selection in Select, Rotate or Connect mode. Rotation, right-button panning and wheel zoom retain selected atoms. An empty click also cancels a pending mouse connection.
Connections can be selected directly. Click any visible section of a connection to toggle its gold outline, or use the Connections inspector tab. Click several to select a group, then choose Delete connections, Delete selected connections in the sidebar, or press Delete / Suppr. Atom and connection selection switch automatically when you click the other type; a selection box selects atoms. The paginated connection list supports filtering and keyboard selection. Text fields and dialogs keep their normal Delete behavior.
In Atom connections, adjust Connection thickness with the slider or numeric multiplier from 0.25 to 4.00. This scales all visible connection cylinders and selection outlines, preserving their three equal colored sections, endpoints and measured distances. The Contact cutoff remains the separate scientific calculation setting. Thickness applies to both publication figures and transparent scene exports, and is saved in projects.
Connection deletion and thickness support Undo / Redo. Deleting a calculated connection stores a display exclusion while preserving the original contact records and atomic structure. Manual connections are removed from the editable list; a matching calculated duplicate is excluded too. Explicitly reconnecting the endpoints restores that connection. Saved projects retain deletions, thickness and selected connections; older projects use thickness 1.00 and no exclusions. Recalculating contacts in the same cell keeps exclusions. Resizing a repeated cell resets exclusions with periodic image anchors, with an explanation in the status message, because those anchors use the displayed cell vectors.
The Coordination polyhedra panel adds transparent, colored solids around chosen central atom types, with optional perimeter edges. Turn on Show polyhedra, choose Central atoms and Surrounding atoms, and set the distance cutoff in angstroms. An empty surrounding-atom selection includes every element. Customize each central type’s color, opacity and outlines; Use atom color restores its element palette. The panel reports how many hulls were drawn and explains insufficient, planar or skipped neighborhoods. Polyhedra are disabled initially and in older projects.
Periodic neighbors are calculated directly from lattice translations, including skew cells and full-cell boundary centers, independently of displayed or calculated connections. A convex hull needs four distinct noncoplanar positions. The distance cutoff defines the neighborhood; it does not determine chemical bonds, symmetry or occupancy configurations. Display limits are 250 centers, 64 neighbors per center and 500,000 candidate images. Overlarge or incomplete neighborhoods are skipped with visible warnings. Atom coordinates and stored sites are preserved. Polyhedron settings participate in Undo/Redo, project downloads and both publication and transparent scene exports.
The scientific workbench keeps the square crystal scene between a tool pane and a structure inspector. On desktop, the two panes scroll independently while the scene stays visible. Structure, Display and Geometry jump to the corresponding tools; categories remain available in the same pane. On smaller screens the workspace stacks without hiding scientific controls.
The main toolbar contains structure/project files, figure exports, Undo/Redo and the Quick guide. Camera and mouse modes sit directly above the scene. The inspector contains selection actions and Overview, Atoms, Connections and Measurements tabs.
Use Search commands, or Ctrl/Command+K, to find a tool by name. Arrow keys choose a result, Enter runs it and Escape closes the search. Unavailable actions explain why they are disabled. Focus scene temporarily hides the tool pane and inspector; Restore panels or Escape brings them back without changing the structure or camera. Projects are downloaded to your device; the interface does not imply a cloud save.
Deleting a boundary image removes its stored periodic site and all equivalent boundary images, plus attached connections. Undo restores the site and selected images. Saved projects and undo history preserve selections of any size; image connections retain both endpoint shifts.
In Define structure manually, selecting FCC, BCC or another preset keeps your atom rows. Choose Replace all atoms to use its reference sites as a new list, or Add atoms to keep your existing sites. FCC/BCC/Simple cubic use their complete 4/2/1-site periodic bases with the element/occupancy assignments shown below. Other presets use the selected reference sites. The existing reference-site controls remain available for applying a subset. Comments are preserved, identical sites are skipped and conflicting occupants are rejected without changing the draft.
Use Add individual atom to choose one of the 118 elements and enter fractional x/y/z coordinates from 0 to 1 and optional occupancy (blank means 1). Adding changes the draft; Create structure commits it to the workspace. Opposite boundary positions refer to the same periodic site.
Choose Transparent scene to download the current 3D view without a background. The export preserves rotation, zoom and pan, the visible cell/axes/connections and selected-atom outlines. It omits the element legend and pending mouse connection preview. Resolution and physical dimensions remain adjustable up to 5,000 DPI within device limits. Rectangular outputs preserve proportions with transparent margins. Export figure continues to fit a publication figure with its optional ball legend and 1 cm spacing.
The a, b and c reference axes use thick solid shafts, broad arrowheads and very bold labels in the live viewer, publication figures and transparent scene downloads. The arrows and lettering scale with export resolution. The Crystal axes checkbox controls their visibility.
Login and Create account provide optional email sign-in, signup, confirmation and password recovery. The owner’s Supabase project is connected and the live forms are enabled; production redirects and email delivery still require verification. The Support button is currently hidden, preserving the owner’s website update; hosted contribution links remain unconfigured. All tools stay free without an account or payment. Projects remain local downloads. See ACCOUNTS_AND_SUPPORT.md for setup status and activation steps.
Feedback offers private bug reports and suggestions without requiring an account. Open Admin directly or use the footer Admin link for the separate password-protected inbox, moderation and site announcement controls. The admin password is configured only as a server-side hash. Private Supabase storage is connected, and feedback submission and moderation were verified on 4 October 2026. See ADMIN_AND_FEEDBACK.md for setup and verification.
Use Python 3.12 or later and Node.js 22.12 or later. The app also supports the Python 3.14 installation used on this Windows setup. From the crystal_studio_web folder, open two terminals.
Python API, on Windows PowerShell:
cd backend
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt
$env:ALLOWED_ORIGINS = "http://localhost:5174,http://127.0.0.1:5174"
.\.venv\Scripts\python.exe -m uvicorn app:app --reload --host 127.0.0.1 --port 8000
On macOS/Linux, use python3 -m venv .venv, .venv/bin/python -m pip install -r requirements.txt, and ALLOWED_ORIGINS="http://localhost:5174,http://127.0.0.1:5174" .venv/bin/python -m uvicorn app:app --reload --host 127.0.0.1 --port 8000.
Browser app, in the second terminal:
cd frontend
npm.cmd ci
npm.cmd run dev
On Windows, npm.cmd avoids the blocked PowerShell npm.ps1 launcher. On macOS/Linux, use npm ci, npm run dev, npm run build and npm test.
Open http://localhost:5174. Set the API URL in the app settings to http://127.0.0.1:8000, or create frontend/.env.local before starting Vite:
VITE_API_BASE_URL=http://127.0.0.1:8000
VITE_BASE_PATH=/
Check http://127.0.0.1:8000/health if the connection is unavailable. Changes to Vite environment variables require restarting the dev server.
Load a bundled example or open a CIF or VESTA file, then inspect the structure in the 3D viewer. Choose ball and stick, spheres, space filling or contacts; adjust element colors; inspect the atom table; and select two or three atoms for a distance or angle. The supplied examples are schematic demonstrations: use your own verified crystal data for scientific results.
In Element colors and sizes, each element has an independent size slider and numeric multiplier from 0.2 to 3.0. Changing hydrogen’s size leaves oxygen’s factor unchanged. The global atom-size control scales all elements together. Per-element factors apply to visible atoms, periodic neighbors, selection outlines, mouse picking and exported figures; they persist in saved projects. Reset returns just that element to 1.00. These are display sizes and do not change atomic coordinates or contact calculations. Older projects use 1.00 for every omitted element factor.
The 3D canvas is square on desktop and mobile. Choose Define structure manually to enter cell lengths, angles and fractional atomic positions without importing a file or waiting for the Python service. Each line contains element x y z [occupancy]; occupancy defaults to 1. Enter one representative of every periodic atomic position, since this editor does not infer symmetry operations. It supports all 118 element symbols, rejects invalid or overlapping periodic sites, and explains when radii or colors use display defaults. Copy current unit cell fills the editor from the loaded structure.
The manual editor offers Cubic, Tetragonal, Orthorhombic, Hexagonal, Trigonal, Monoclinic and Triclinic cell presets, plus FCC, BCC and Simple cubic reference templates. Linked cell lengths and fixed angles update automatically; Custom cell unlocks all six parameters. Trigonal uses rhombohedral axes and monoclinic uses the unique b axis. These templates define geometry and reference positions; they do not determine a material’s actual symmetry or generate space-group/Wyckoff equivalents. The constraints follow IUCr conventions.
Expand Place atoms at reference sites to select origin, body, face or edge centers, choose an element from all 118 symbols, and set each occupancy. Add to existing atom rows keeps existing text and comments, skips identical periodic sites, and rejects conflicting species/occupancies without changing the draft. Replace all atom rows is an explicit alternative. Cubic template defaults contain one origin site for Simple cubic, two sites for BCC, and four sites for FCC; equivalent opposite boundary sites appear once. IUCr centering coordinates. Choosing a different preset keeps atom rows intact; copying the current unit cell returns to Custom so its exact geometry is retained.
Show full unit cell is enabled by default in the manual editor. FCC displays 8 corners and 6 face centers (14 sphere positions); BCC displays 8 corners and 1 body center (9); Simple cubic displays 8 corners. These are periodic images, so saved FCC/BCC/Simple cubic structures still contain 4/2/1 representatives. The Full unit cell checkbox in Representation switches between the complete cell and its stored basis. Boundary spheres follow each element’s color and size and appear in both figure and transparent scene exports. This display setting survives project downloads. For measurements and manual connections, select the stored positions in the Atoms table; boundary images are not separate connection endpoints. Periodic contacts independently controls the faint neighbors used for calculated contacts.
Select exactly two atoms in the viewer or atom table, then choose Connect selected atoms in the Atom connections panel. Choose calculated contacts, manual connections only, or both. Manual links use the selected displayed positions and are included in projects and figure exports. Calculate contacts asks the Python service for covalent-radius periodic contacts. Changing supercell dimensions retains connections whose selected atoms remain inside the new cell; links to removed atoms are removed with a status message.
Choose Connect with mouse in the viewer toolbar to draw a manual connection directly: drag from one atom to another, or click the first atom and then the second. A preview marks the pending endpoint. Escape, clicking empty space, or turning the mode off cancels an unfinished connection. Duplicate and self connections are prevented. Drag empty space to rotate; right-drag pans and the wheel zooms. Turn the mode off to resume ordinary click selection. The atom table and Connect selected atoms remain available for keyboard operation.
Select atoms in the 3D view or Atoms table and press Delete / Suppr, or choose Delete selected atoms in the viewer toolbar. Attached calculated and manual connections are removed, surviving atom numbers are updated, and the edited structure persists in project downloads. Keyboard deletion is inactive while typing in fields, inside an open dialog, or during calculations/exports. At least one atom must remain. Deleting a selected instance in a repeated supercell keeps the remaining displayed supercell as the new editable unit cell and resets repetitions to 1 × 1 × 1; its lattice and coordinates are preserved. The camera stays in place, and the source notes identify the edited composition and symmetry.
Each connection has three equal-length sections: the first atom’s color, neutral grey, and the second atom’s color. This applies to manual and calculated connections, including periodic contacts, figures and transparent scene exports. Changing an element color updates its connection ends immediately. Atom sizes and the contact cutoff continue to have their existing independent effects.
Download a project as JSON to keep a portable copy and restore it later. PNG and PDF exports are generated in your browser with the chosen physical size and DPI; PDFs embed a raster figure rather than vector geometry. Project downloads and images remain usable independently of the Python service; keep a downloaded JSON copy of work you need to retain.
The element legend uses large shaded balls and clear element symbols in a vertical list, following your chosen element colors. In PNG and PDF exports, it stays fixed in the upper-left corner, independent of camera rotation and zoom. The horizontal distance from the legend’s visible edge to the nearest rendered atom is 1 cm, rounded to the nearest output pixel at your chosen DPI. Export fits the structure to the available area while retaining the viewing angle and restores the live camera afterward. Longer lists shrink uniformly to fit one vertical column. Turn off the legend in export settings when you want a figure containing only the structure. Axis labels follow the crystal-axes visibility control independently of the legend.
Exports default to 8 × 8 cm at 1,200 DPI. You can select up to 5,000 DPI, within the device’s graphics limit, 8,192 pixels per side, and a 32-million-pixel budget. For example, a 2.5 cm square at 5,000 DPI produces 4,921 × 4,921 pixels; a 5 cm square at 2,400 DPI produces 4,724 × 4,724 pixels. If the requested physical size is too large, Fit size to device reduces the dimensions without reducing the chosen DPI. The UI reports a supported square size at the selected resolution. Choose Transparent - no background for a background-free PNG or PDF. The PDF keeps the alpha mask and requested physical page size; its image remains raster rather than vector geometry. An unfinished mouse-connection preview is excluded from figures.
Uploaded source files are sent to the configured Python service for processing. The application does not persist them on the server or publish them to GitHub. Put private reference documents outside the public repository; the included .gitignore excludes common local upload/export folders. The API uses bounded processing, and the 3D rendering stays in the browser rather than requiring server-side VTK.
The Python service accepts files up to 2 MiB, limits expanded structures to 2,000 atoms and 20,000 contacts, and accepts supercell repetitions from 1 to 5 on each axis within the atom limit. The workspace controls offer repetitions from 1 to 4 on each axis. CIF symmetry and non-orthogonal cells are preserved; unsupported VESTA cell transformations are rejected. Warnings identify partial occupancy or mixed sites that need scientific interpretation. Displayed contacts are estimates based on covalent-radius distances, not proof of chemical bonds.
Create a public GitHub repository such as crystal-studio-web and push this folder’s contents to its main branch. Keep frontend/package-lock.json committed; the workflow uses npm ci. GitHub Pages is available for public repositories on GitHub Free. GitHub Pages availability
render.yaml defines a Python web service with the Free plan, working directory backend, Python 3.12.10, and health path /health.ALLOWED_ORIGINS, enter your Pages origin, for example https://YOUR-USERNAME.github.io. Do not append the repository name or a trailing slash. For multiple permitted origins, separate them with commas. This is an origin allowlist, not an API key.https://YOUR-SERVICE.onrender.com. Open https://YOUR-SERVICE.onrender.com/health to check it.PYTHON_API_URL containing the API URL, without /health. This URL is public configuration.main. The published viewer is at https://YOUR-USERNAME.github.io/YOUR-REPOSITORY/.The workflow builds frontend/dist with VITE_BASE_PATH=/<repository-name>/ and VITE_API_BASE_URL from PYTHON_API_URL, then uploads and deploys the Pages artifact. It uses GitHub’s workflow token; you do not need to put account credentials in the application. If the API URL changes, update the repository variable and run the Pages workflow again. You can also select a different API URL in the app settings.
Render’s start command is uvicorn app:app --host 0.0.0.0 --port $PORT. There is no Docker setup or database to provision. The Free plan is selected explicitly with plan: free; review the service summary before creating it. Render Blueprint fields
Render currently pauses a free API after 15 minutes without traffic. Its next request can take about one minute while the service starts; allow it to wake and retry if necessary. The workspace receives 750 free instance hours per calendar month, shared across its free services. The local filesystem is ephemeral and cannot be used as permanent project storage. Included bandwidth and build quotas also apply. These limits were checked on 2 October 2026. Render free-service limits
The viewer itself stays available on GitHub Pages while the API sleeps. Downloads and browser exports do not require a paid render worker. Use the free service for occasional or personal use; it is not an always-running backend.
cd frontend
npm.cmd ci
npm.cmd run build
The output is frontend/dist. For a local preview build, use VITE_BASE_PATH=/; the Pages workflow sets the repository path automatically.
Run the backend tests in a fresh terminal after creating the virtual environment:
cd backend
.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
.\.venv\Scripts\python.exe -m pytest
Run the frontend unit tests from the frontend folder:
cd frontend
npm.cmd test
For the browser integration check, keep both local servers running on ports 8000 and 5174, install the frontend development dependencies with npm.cmd ci, and have Google Chrome installed. Run this command from the crystal_studio_web project root:
node tests/browser.mjs
The browser check uses the real local Python API to exercise structure imports, display controls, project save/load, measurements and image/PDF downloads. If Chrome is installed in a custom location, update the browser executable configuration in tests/browser.mjs.
CRYSTAL_API_URL and CRYSTAL_URL override the browser regression check’s API and frontend addresses. The additional tests/improvements.py browser check covers manual input, custom connections, square layouts, transparent exports, physical legend spacing, high-resolution PNGs and PDF alpha masks. It requires Python Playwright and installed Chrome; run python tests/improvements.py --api http://127.0.0.1:8001 when testing an API on port 8001, or omit the argument for that default. Use --url to check a built or deployed frontend and --api to choose its backend. Browser artifacts are kept in the excluded artifacts/ directory.
Run python tests/mouse-and-sizing.py for actual mouse drags/clicks, canceled connections, ordinary camera interaction, independent element-size persistence and a real 5,000 DPI PNG. It also accepts --url for built or deployed frontends and uses installed Chrome with Python Playwright.
Run python tests/scene-capture.py against the local Vite source server for independent current-view framing, transparent rectangular padding, excluded connection previews and restoration after an encoding failure. The optional-account browser checks and configuration are described in ACCOUNTS_AND_SUPPORT.md.
Run python tests/crystal-presets.py with Python Playwright and Chrome to verify all ten preset choices, linked parameters, mixed reference elements, occupancy, safe append/replace, periodic duplicate handling, saved geometry and mobile layouts. It accepts --url for built or deployed frontends.
Run python tests/full-cell.py for full-cell display, basis preservation, project persistence and real rendered/exported boundary spheres. Use --url <site> --ui-only for a built or deployed frontend; independent viewer checks use the local Vite source server.
/health endpoint, then allow for Render’s wake-up delay.ALLOWED_ORIGINS to the exact frontend origin, such as https://YOUR-USERNAME.github.io, without /YOUR-REPOSITORY/, and redeploy the API.PYTHON_API_URL, rerun the workflow, then check whether the app settings contain a saved override.The deployment workflow follows GitHub’s custom Pages workflow documentation. Account creation, repository publication and cloud deployment are performed in your GitHub and Render accounts.
Run python tests/administration.py --url <frontend> with Python Playwright and installed Chrome for isolated feedback/admin browser checks. Every community endpoint is intercepted; these checks never submit live feedback or credentials. Backend tests include administrator sessions, private REST storage, rate limits and schema/error bounds.
After a production build, python tests/admin-route.py checks both direct admin URL forms on a plain static server, refresh, asset paths, password protection, account callbacks, unsaved workspace preservation and mobile keyboard focus. For a relative-base build, repeat with --base-path /nested-tool/. These route checks use isolated API responses and send no live credentials or feedback.
tests/bug-regressions.py --url <frontend> checks error recovery, service-test races, cancelled project loading, keyboard/mobile access and WebGL/storage fallbacks. tests/viewer-resources.py --url <source-frontend> checks actual GPU buffers across display changes and exports. tests/skew-boundary.py --url <frontend> --api <scientific-api> uses a synthetic triclinic structure to verify boundary-atom stability and saved-project reloads through the stateless Python service. See VALIDATION.md for the current results and scope.