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

zcpbx

MolstarViewer

Public
Like
MolstarViewer
Home
Code
14
frontend
2
routes
13
shared
2
utils
.vtignore
AGENTS.md
CHANGELOG.md
MIGRATION.md
QUICKSTART.md
README.md
deno.json
index.html
H
index.tsx
molstar-viewer.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: v344
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
│   ├── home.tsx                # Homepage listing all apps
│   ├── viewer.tsx              # Viewer app route
│   ├── docking-viewer.tsx      # Docking viewer route
│   ├── mesoscale-explorer.tsx  # Mesoscale explorer route
│   └── mvs-stories.tsx         # MVS stories route
├── frontend/                    # Client-side TSX components
│   ├── apps/                   # Individual app components
│   │   ├── viewer.tsx
│   │   ├── docking-viewer.tsx
│   │   ├── mesoscale-explorer.tsx
│   │   └── mvs-stories.tsx
│   ├── styles/                 # CSS files
│   │   └── molstar.css         # Compiled Molstar styles
│   └── README.md
├── 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 handles its specific path:

/** @jsxImportSource https://esm.sh/react@18.2.0 */ import { Hono } from "jsr:@hono/hono@4"; import { renderToString } from "https://esm.sh/react-dom@18.2.0/server?deps=react@18.2.0,react-dom@18.2.0"; import ViewerApp from "../frontend/apps/viewer.tsx"; const app = new Hono(); app.get("/viewer", async (c) => { const html = renderToString(<ViewerApp />); return c.html(html); }); export default app;

Frontend (TSX Components)

Each app is a self-contained TSX component that returns a complete HTML document:

Create val
/** @jsxImportSource https://esm.sh/react@18.2.0 */ export default function ViewerApp({ molstarCss }: { molstarCss: string }) { return ( <html lang="en"> <head> <meta charSet="UTF-8" /> <title>Mol* Viewer</title> <style dangerouslySetInnerHTML={{ __html: molstarCss }} /> </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> ); }

Server-Side Rendering

  • Routes use renderToString from React to server-render components
  • CSS is injected inline from compiled Molstar stylesheets
  • Client-side Molstar initialization happens via inline module scripts
  • This avoids issues with JSR imports in server-side contexts

🔧 Development

Current Status

The project is currently scaffolded with:

  • ✅ Top-level route structure (Val Town blog style)
  • ✅ Main Hono app in index.tsx
  • ✅ Separate route files for each app
  • ✅ TSX components for each app
  • ✅ Viewer app fully functional with JSR imports
  • ✅ Compiled Molstar CSS integration
  • ⏳ Docking viewer (scaffolded)
  • ⏳ Mesoscale explorer (scaffolded)
  • ⏳ MVS Stories (scaffolded)

Key Implementation Details

  1. CSS Handling: Molstar CSS is read from frontend/styles/molstar.css and injected inline
  2. Client-Side Initialization: Molstar viewer is initialized in browser using inline <script type="module">
  3. JSR Imports: Work only in client-side context, not in server-side rendering
  4. Error Handling: app.onError unwraps Hono errors to show full stack traces

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

  • All components use the /** @jsxImportSource https://esm.sh/react@18.2.0 */ pragma
  • 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
  • Server-side rendering uses renderToString from React
  • Client-side scripts are injected using template literals in JSX
  • Molstar CSS is loaded server-side and injected inline

Val Town Specifics

  • No backend/ folder - routes at top level like Val Town blog
  • Main entry point is index.tsx (not backend/index.tsx)
  • 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/ if adding a new page
  2. Create corresponding component in frontend/apps/ for the UI
  3. Mount the route in index.tsx
  4. Keep shared types in shared/types.ts
  5. Use JSR imports for Molstar dependencies
  6. 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.