mirror of
https://github.com/storytold/craft-anything.git
synced 2026-11-05 20:47:45 +01:00
f64ae3bf3c
A native, pure-Rust app that shows anyone how a piece of software works, with evidence-backed answers, then helps them rebuild it. It ships a desktop app, a CLI and an MCP server, all driven by one engine. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
90 lines
4.0 KiB
Markdown
90 lines
4.0 KiB
Markdown
# Hosting Craft Anything for the web
|
|
|
|
`craft-anything-web-<version>.zip` (from the GitHub release, or `packaging/web/package.sh`) holds a
|
|
static site in `craft-anything-web-<version>/`:
|
|
|
|
| File | What it is |
|
|
|---|---|
|
|
| `index.html` | The page. It loads everything through relative URLs. |
|
|
| `craft-anything-web-<hash>.js` | wasm-bindgen glue (generated, ES module) |
|
|
| `craft-anything-web-<hash>_bg.wasm` | The app |
|
|
| `_headers`, `.htaccess` | Sample header rules for Netlify/Cloudflare Pages and Apache |
|
|
|
|
There is no server-side code and no hand-written JavaScript: the glue is generated by
|
|
wasm-bindgen from the Rust sources (`apps/craft-anything-web`). Upload the folder's contents anywhere
|
|
that serves static files.
|
|
|
|
The web viewer runs entirely on the visitor's device: a dropped or picked file is read in the
|
|
browser and never uploaded. It uses the built-in, pure-Rust analyzers only (formats, disassembly,
|
|
JavaScript bundles); running programs, external engines and AI backends need the desktop app. A
|
|
browser with WebGPU or WebGL2 is required.
|
|
|
|
## Size
|
|
|
|
`packaging/web/package.sh` fails the build if the wasm grows past 24 MiB: Cloudflare Pages and
|
|
Workers static assets reject any file over **25 MiB**, so a release can't ship a file a common host
|
|
refuses.
|
|
|
|
## Required server settings
|
|
|
|
- **MIME type:** serve `.wasm` as `application/wasm`. Browsers refuse to stream-compile it under
|
|
any other type, and the app then loads slowly or not at all. Serve `.js` as `text/javascript`.
|
|
Most hosts already do both. For nginx, check that `mime.types` has `application/wasm wasm;`.
|
|
- **Compression:** turn on gzip or Brotli for `.wasm`, `.js` and `.html`. Brotli usually
|
|
shrinks the wasm to a quarter of its size. You can also
|
|
precompress (`brotli -k *.wasm`) and let the server send `Content-Encoding: br`.
|
|
- **Caching:** `Cache-Control: public, max-age=31536000, immutable` on the hashed `.wasm` and
|
|
`.js` files, and `no-cache` on `index.html`.
|
|
- **HTTPS:** WebGPU (and the clipboard) only work in a secure context, which means `https://`
|
|
or `http://localhost`. Over plain HTTP elsewhere, the app falls back to WebGL2.
|
|
- **No special isolation headers:** Craft Anything doesn't use `SharedArrayBuffer`, so it doesn't
|
|
need `Cross-Origin-Opener-Policy` or `Cross-Origin-Embedder-Policy`. If your site already sends
|
|
COEP `require-corp`, also send `Cross-Origin-Resource-Policy: same-origin` (or `cross-origin`
|
|
when the files live on a CDN) on the app's files.
|
|
|
|
nginx example:
|
|
|
|
```nginx
|
|
location /craft-anything/ {
|
|
types { application/wasm wasm; text/javascript js; text/html html; }
|
|
gzip on;
|
|
gzip_types application/wasm text/javascript text/html;
|
|
location ~* \.(wasm|js)$ { add_header Cache-Control "public, max-age=31536000, immutable"; }
|
|
location ~* index\.html$ { add_header Cache-Control "no-cache"; }
|
|
}
|
|
```
|
|
|
|
Local test: `python3 -m http.server 8767` inside the folder, then open http://localhost:8767/.
|
|
|
|
## Embedding in a page (iframe)
|
|
|
|
```html
|
|
<iframe
|
|
src="https://example.com/craft-anything/"
|
|
title="Craft Anything"
|
|
style="width: 100%; height: 720px; border: 0;"
|
|
allow="fullscreen; clipboard-read; clipboard-write"
|
|
allowfullscreen>
|
|
</iframe>
|
|
```
|
|
|
|
- The app fills the iframe and follows its size, so size the iframe and not the app.
|
|
- Keyboard shortcuts go to the iframe after the user clicks into it, as with any embedded app.
|
|
- **Sandboxed iframes** need at least `sandbox="allow-scripts allow-same-origin allow-popups"`
|
|
(`allow-popups` lets Help links open in a new tab).
|
|
- Don't send `X-Frame-Options: DENY` or a `frame-ancestors` CSP that excludes the embedding page.
|
|
|
|
## Renderer
|
|
|
|
Craft Anything renders with wgpu: **WebGPU** when the browser has it, otherwise **WebGL2**.
|
|
|
|
## Smoke test (headless Chrome)
|
|
|
|
Headless Chrome has no WebGPU adapter, so it runs on WebGL2 through SwiftShader:
|
|
|
|
```sh
|
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --headless=new \
|
|
--use-angle=swiftshader --enable-unsafe-swiftshader --window-size=1440,900 \
|
|
--timeout=30000 --screenshot=craft-anything-web.png "http://127.0.0.1:8767/"
|
|
```
|