• Townie
    AI
  • Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
zcpbx

zcpbx

MolstarViewer

Public
Like
MolstarViewer
Home
Code
13
frontend
10
routes
6
shared
2
utils
.vtignore
AGENTS.md
CHANGELOG.md
MIGRATION.md
QUICKSTART.md
README.md
deno.json
index.html
index.tsx
Branches
1
Pull requests
Remixes
History
Environment variables
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
README.md
Code
/
README.md
Search
…
Viewing readonly version of main branch: v505
View latest version
README.md

Molstar Viewer Apps

A collection of Molstar molecular visualization applications built for Val Town, using JSR imports and TSX.

πŸš€ Quick Start

This Val serves four different Molstar visualization applications:

  • Viewer 🧬 - Standard Mol* viewer for visualizing molecular structures
  • Docking Viewer πŸ”¬ - Specialized viewer for molecular docking results
  • Mesoscale Explorer πŸ”­ - Explore mesoscale biological structures
  • MVS Stories πŸ“– - Interactive molecular visualization stories

πŸ“ Project Structure

Following the Val Town blog pattern with routes at the top level:

MolstarViewer/
β”œβ”€β”€ index.tsx                    # Main Hono app (entry point)
β”œβ”€β”€ routes/                      # Route handlers (return HTML directly)
β”‚   β”œβ”€β”€ home.tsx                # Homepage listing all apps
β”‚   β”œβ”€β”€ viewer.tsx              # Viewer route (returns HTML string)
β”‚   β”œβ”€β”€ viewer/                 # Viewer-specific modules (if needed)
β”‚   β”œβ”€β”€ docking-viewer.tsx      # Docking viewer route
β”‚   β”œβ”€β”€ docking-viewer/         # Docking-specific modules (if needed)
β”‚   β”œβ”€β”€ mesoscale-explorer.tsx  # Mesoscale route
β”‚   β”œβ”€β”€ mesoscale-explorer/     # Mesoscale-specific modules (if needed)
β”‚   β”œβ”€β”€ mvs-stories.tsx         # MVS stories route
β”‚   └── styles/                 # CSS files
β”‚       └── molstar.css         # Compiled Molstar styles
β”œβ”€β”€ shared/                      # Shared types and utilities
β”‚   β”œβ”€β”€ types.ts
β”‚   └── README.md
β”œβ”€β”€ utils/                       # Utility functions
└── README.md                    # This file

πŸ› οΈ Technology Stack

  • Runtime: Val Town (Deno-based)
  • Framework: Hono v4 from JSR
  • UI: React 18.2.0 via esm.sh
  • Molstar: JSR package jsr:@zachcp/molstar@5.3.17
  • Language: TypeScript/TSX

πŸ“¦ JSR Imports

All dependencies are imported using the JSR protocol:

Molstar from JSR

import { Viewer } from "jsr:@zachcp/molstar@5.3.17";

Available exports from jsr:@zachcp/molstar:

  • . (main export - includes Viewer class)
  • ./plugin-ui
  • ./plugin
  • ./plugin-state
  • ./canvas3d
  • ./data
  • ./state
  • ./task
  • ./util
  • ./extensions

Hono from JSR

import { Hono } from "jsr:@hono/hono@4";

Why JSR?

JSR (JavaScript Registry) provides native Deno/TypeScript support and works seamlessly in Val Town's runtime environment.

πŸ—οΈ Architecture

Main Entry Point

The top-level index.tsx is the main Hono app that imports and mounts all routes:

/** @jsxImportSource https://esm.sh/react@18.2.0 */ import { Hono } from "jsr:@hono/hono@4"; import homeRoutes from "./routes/home.tsx"; import viewerRoute from "./routes/viewer.tsx"; // ... other routes const app = new Hono(); app.onError((err, c) => { throw err; // Unwrap errors for debugging }); app.route("/", homeRoutes); app.route("/", viewerRoute); // ... mount other routes export default app.fetch;

Routes

Each route is a separate Hono app that returns HTML directly using template literals:

/** @jsxImportSource https://esm.sh/react@18.2.0 */ import { Hono } from "jsr:@hono/hono@4"; import { readFile } from "https://esm.town/v/std/utils@85-main/index.ts"; const app = new Hono(); app.get("/viewer", async (c) => { const molstarCss = await readFile("/routes/styles/molstar.css", import.meta.url); return c.html(` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Mol* Viewer</title> <script src="https://esm.town/v/std/catch"></script> <style>${molstarCss}</style> </head> <body> <div id="molstar-container">Loading Mol* Viewer...</div> <script type="module"> import { Viewer } from "jsr:@zachcp/molstar@5.3.17"; window.addEventListener("DOMContentLoaded", async () => { const container = document.getElementById("molstar-container"); if (container) { const viewer = await Viewer.create(container, { layoutIsExpanded: true, layoutShowControls: true, }); } }); </script> </body> </html> `); }); export default app;

HTML Templates

  • Routes return HTML directly using JavaScript template literals
  • No React server-side rendering needed - simpler and faster
  • CSS is injected inline from compiled Molstar stylesheets
  • Client-side Molstar initialization happens via inline module scripts
  • JSR imports work perfectly in client-side <script type="module"> tags

πŸ”§ Development

Current Status

The project is currently scaffolded with:

  • βœ… Top-level route structure (Val Town blog style)
  • βœ… Main Hono app in index.tsx
  • βœ… Routes return HTML directly (no React SSR)
  • βœ… Separate route files for each app
  • βœ… Viewer app fully functional with JSR imports
  • βœ… Compiled Molstar CSS integration
  • βœ… No separate frontend/ or backend/ folders
  • ⏳ Docking viewer (scaffolded)
  • ⏳ Mesoscale explorer (scaffolded)
  • ⏳ MVS Stories (scaffolded)

Key Implementation Details

  1. Simple HTML Templates: Routes return HTML strings using template literals - no React SSR
  2. CSS Handling: Molstar CSS is read from routes/styles/molstar.css and injected inline
  3. Client-Side Initialization: Molstar viewer is initialized in browser using inline <script type="module">
  4. JSR Imports: Work perfectly in client-side <script type="module"> tags
  5. Error Handling: app.onError unwraps Hono errors to show full stack traces
  6. Error Catching: Include https://esm.town/v/std/catch to capture client-side errors

Next Steps

  1. Implement remaining apps:
    • Docking Viewer: Load and compare docking results
    • Mesoscale Explorer: Load mesoscale structures
    • MVS Stories: Story navigation and playback
  2. Add interactive controls for each viewer
  3. Add loading states and error handling in UI
  4. Implement app-specific features:
    • Viewer: Load PDB structures by ID
    • Add URL parameters for structure loading
    • Add preset views and controls

πŸ“š Resources

  • Mol* Website
  • Val Town Documentation
  • JSR Package Registry
  • Hono Framework
  • Val Town Blog Example - Structure inspiration

πŸ“ Notes

Important Patterns

  • Routes use template literals to return HTML strings directly (no React)
  • JSR imports use the jsr: protocol (e.g., jsr:@zachcp/molstar@5.3.17)
  • Routes are separate Hono apps that get mounted in main index.tsx
  • All route logic lives in the routes/ folder
  • Client-side scripts use <script type="module"> for JSR imports
  • Molstar CSS is loaded server-side and injected inline via template literals

Val Town Specifics

  • No backend/ or frontend/ folders - everything colocated in routes/
  • Main entry point is index.tsx at project root
  • Routes and components live together in routes/ folder
  • Use readFile utility for reading project files
  • JSR imports work seamlessly in Val Town's Deno runtime

🀝 Contributing

When adding new features:

  1. Create a new route file in routes/ (e.g., my-feature.tsx)
  2. Route should return HTML using template literals with c.html()
  3. Include <script type="module"> for client-side initialization
  4. Mount the route in index.tsx with app.route("/", myFeatureRoute)
  5. Keep shared types in shared/types.ts
  6. Use JSR imports for Molstar dependencies in client-side scripts
  7. Follow Val Town best practices from AGENTS.md

πŸ“„ License

Copyright (c) 2018-2025 mol* contributors, licensed under MIT

FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
DocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Open Source Pledge
Terms of usePrivacy policyAbuse contact
Β© 2025 Val Town, Inc.