Commit4b53dfereplaced the Go goldmark extension with JS text-node linkification, making bare ifc:// URL rendering work entirely client-side. No Forgejo rebuild is needed for any feature. - Remove "Optional: Go patch" section from README.md - Remove Go tests from Development section - Update forgejo/README.md feature table, prerequisites, and deploying sections - Remove "Applying the patch", "Configuration" (PREVIEW_SERVICE_URL), and "Upgrading Forgejo" (Go-specific steps) sections from forgejo/README.md - Update forgejo/SETUP_LOCAL.md: bare URLs now work; remove Step 6 (app.ini) - Delete forgejo/go.patch (dead code — ifc_url.go was removed in4b53dfe) - Add underscore caveat note wherever bare URL support is described Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
Forgejo integration
This directory contains assets for the ifcurl preview extension. The features split into two tiers by what infrastructure they require.
Feature overview
| Feature | What it needs | Forgejo rebuild? |
|---|---|---|
| "View in 3D" button on file/history pages | ifcurl.js + ifcurl service |
No |
| Browser IFC viewer | viewer.html static asset |
No |
| PR diff 3D render | ifcurl.js + ifcurl service + Nginx proxy |
No |
[title](ifc://...) links in markdown → inline preview |
ifcurl.js + ifcurl service + Nginx proxy |
No |
Bare ifc://... text in markdown → inline preview |
ifcurl.js (JS text-node linkification) |
No |
All features work with static asset deployment only — no Forgejo rebuild required.
ifcurl.js handles both <a href="ifc://..."> links produced by Goldmark's
standard link parser and bare ifc://... text nodes, replacing both with preview
figures at page load.
Bare URL caveat: bare ifc:// URLs where the path or query parameters
contain matched underscores (e.g. _model_v2.ifc) may be split by Goldmark's
emphasis parser before ifcurl.js can linkify them. Use the explicit
[label](ifc://...) form in those cases — the viewer's Issue button always
generates this safe form.
The PR diff feature requires a reverse proxy (e.g. Nginx) to expose the
ifcurl service at the same origin as Forgejo. This is because the diff image is
fetched by the browser (not by Forgejo's server), and browsers block cross-origin
image requests to plain http://localhost URLs. Most production Forgejo
deployments already sit behind Nginx for TLS termination; adding two
proxy_pass lines is the only extra step.
Directory layout
forgejo/
custom/public/assets/
viewer.html ← browser IFC viewer (no rebuild needed)
viewer-url.js ← ifc:// URL parse/build/resolve logic (ES module)
viewer-util.js ← shared pure utilities: parseCommitHref, isSimpleTypeSelector, etc.
ifcurl.js ← "View in 3D" + PR diff injection (ES module, no rebuild needed)
templates/custom/
footer.tmpl ← loads ifcurl.js (no rebuild needed)
server-config/
ifcurl-api.service ← systemd unit for the API service (git + caching)
ifcurl-render.service ← systemd unit for the render isolation service
gitconfig-ifcmerge ← git merge driver registration for /etc/gitconfig
gitattributes ← system-wide gitattributes for bare repos
Local setup (Windows + Docker)
For a self-contained local deployment of Forgejo + ifcurl on Windows using Docker, see SETUP_LOCAL.md.
Prerequisites
- ifcurl API service + render service running (see Running the preview service)
- Nginx (or equivalent) in front of Forgejo if PR diff images are wanted
No Forgejo source tree or Go toolchain is required — all features work with static asset deployment.
Building the viewer JavaScript bundle
The viewer loads Three.js, ThatOpen components, and JSZip from locally-bundled files rather than CDNs. The bundle files are committed to the repository, so you only need to re-run the build when upgrading a dependency version.
Prerequisites
Node.js 18+ and npm (used only at build time; not required on the server).
Run the build
cd forgejo/
npm install # installs pinned versions from package-lock.json
npm run build # produces the four files below
npm test # run JavaScript unit tests (viewer-url.js, viewer-util.js)
Output files (committed to the repository):
| File | Source | Purpose |
|---|---|---|
custom/public/assets/viewer-deps.js |
three + @thatopen/components + @thatopen/components-front + jszip | Main viewer dependencies |
custom/public/assets/fragments-worker.js |
@thatopen/fragments worker | IFC parsing web worker |
custom/public/assets/web-ifc.wasm |
web-ifc | IFC geometry kernel (single-threaded) |
custom/public/assets/web-ifc-mt.wasm |
web-ifc | IFC geometry kernel (multi-threaded) |
The node_modules/ directory is gitignored and is never deployed.
Upgrading a dependency
Edit the version number in package.json, then:
cd forgejo/
npm install # updates package-lock.json
npm run build # regenerates the bundle from the new version
git add package.json package-lock.json custom/public/assets/
git commit -m "viewer: upgrade <package> to vX.Y.Z"
Deploying custom assets (no rebuild required)
These files can be updated at any time without recompiling Forgejo.
Viewer and URL logic
sudo mkdir -p /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/viewer.html /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/viewer-url.js /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/viewer-util.js /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/viewer-deps.js /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/fragments-worker.js /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/web-ifc.wasm /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/web-ifc-mt.wasm /var/lib/forgejo/custom/public/assets/
sudo cp forgejo/custom/public/assets/ifcurl.js /var/lib/forgejo/custom/public/assets/
ifcurl.js is an ES module and imports from viewer-util.js at the same path, so both files must be deployed together.
Served at /assets/viewer.html, /assets/viewer-deps.js, etc.
Note: the correct CustomPath is /var/lib/forgejo/custom (Forgejo's default when FORGEJO_CUSTOM is
not set). Do not use /etc/forgejo/public/assets/ — Forgejo does not serve from there.
"View in 3D" footer template
sudo mkdir -p /var/lib/forgejo/custom/templates/custom/
sudo cp forgejo/templates/custom/footer.tmpl /var/lib/forgejo/custom/templates/custom/
sudo systemctl restart forgejo
Running the preview service
The service is split into two systemd units for security isolation:
-
ifcurl-api — handles HTTP requests, git fetching, and caching. Has network access and can call git CLI tools. Holds credentials (
/etc/ifcurl/env). Delegates all IFC rendering to ifcurl-render over a Unix socket. -
ifcurl-render — handles IFC parsing and rendering via ifcopenshell and pyvista. Has no network access, no credentials, and
execve/execveatare blocked by systemd. Communicates only over the Unix socket.
This split limits the blast radius if a crafted IFC file achieves code execution in the render process: it cannot reach git hosts or read credentials.
As systemd services (recommended)
# Create the two service users
sudo useradd --system --no-create-home --shell /usr/sbin/nologin ifcurl
sudo useradd --system --no-create-home --shell /usr/sbin/nologin ifcurl-render
# Add ifcurl user to ifcurl-render group so it can read the socket
sudo usermod -aG ifcurl-render ifcurl
# Install the units (edit AllowedHosts and port in ifcurl-api.service first)
sudo cp forgejo/server-config/ifcurl-api.service /etc/systemd/system/
sudo cp forgejo/server-config/ifcurl-render.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now ifcurl-render
sudo systemctl enable --now ifcurl-api
Edit the ExecStart line in ifcurl-api.service to set your Forgejo hostname:
ExecStart=/usr/local/bin/ifcurl serve \
--host 127.0.0.1 \
--port 8000 \
--allowed-hosts git.example.com
Cache limits and other environment variables for the API service go in
/etc/ifcurl/env (one KEY=value per line):
IFCURL_CACHE_MAX_GB=10
IFCURL_T2_MAX=16
Render-side environment variables (timeouts, memory limits) go in
/etc/ifcurl/render-env:
IFCURL_SANDBOX_TIMEOUT=180
IFCURL_SANDBOX_MEMORY_MB=2048
Single-service mode (testing / simple deployments)
Without IFCURL_RENDER_SOCKET set, the API service handles rendering directly
in its own subprocess sandbox. This is simpler to set up but offers less
isolation.
ifcurl serve --allowed-hosts git.example.com
For a Forgejo instance on a non-standard port (e.g. 3000 for local dev):
ifcurl serve --allowed-hosts localhost:3000
--allowed-hosts accepts a comma-separated list. Omitting it allows all
non-private remote hosts, which is unsafe if the service is reachable from
untrusted clients.
Nginx reverse-proxy for PR diff images
The PR diff viewer (Case 3 in footer.tmpl) injects <img src="/render_diff?…">
tags that the browser must fetch. The browser resolves /render_diff against
the Forgejo origin, so the ifcurl service must be reachable at the public URL.
Add these proxy locations to the Nginx virtual host that fronts Forgejo:
# ifcurl preview service — served under the same origin as Forgejo
location /preview {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_read_timeout 120s;
}
location /render_diff {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_read_timeout 120s;
}
location /bcf {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_read_timeout 120s;
}
Without this proxy the "View in 3D" button (Case 1/2) still works — it opens the viewer HTML which fetches the IFC file directly. The PR diff images (Case 3) will silently fail to load until the proxy is in place.
IFC merge driver (ifcmerge)
Configuring ifcmerge as the git merge driver for .ifc files lets Forgejo
automatically merge IFC pull requests instead of marking them as conflicted.
How Forgejo checks mergeability
Forgejo (with git ≥ 2.38) uses git merge-tree --write-tree to perform a
trial merge in the bare repository. This command does invoke configured
merge drivers — confirmed by testing. With ifcmerge set up correctly,
the "can be automatically merged" indicator on a PR reflects ifcmerge's
actual result, not a naive text-conflict check.
Important: bare repositories do not read committed .gitattributes files
from the tree. The merge driver must be declared via a system-wide
core.attributesFile setting in /etc/gitconfig.
Prerequisites
ifcmerge is a single Perl script from
github.com/brunopostle/ifcmerge.
Download and install it on the Forgejo server:
curl -o /usr/local/bin/ifcmerge \
https://raw.githubusercontent.com/brunopostle/ifcmerge/main/ifcmerge
chmod +x /usr/local/bin/ifcmerge
Verify it is on PATH for the forgejo system user:
sudo -u forgejo which ifcmerge
Deploy the config files
# System-wide gitattributes (the critical piece for bare repos)
sudo cp forgejo/server-config/gitattributes /etc/gitattributes
# Append merge driver registration + core.attributesFile to /etc/gitconfig
sudo git config --system include.path /path/to/ifcurl/forgejo/server-config/gitconfig-ifcmerge
Or apply the blocks from server-config/gitconfig-ifcmerge directly into
/etc/gitconfig by hand.
Merge direction
The invariant is that step-IDs in main/master must never be renumbered,
because existing cross-references depend on them. The correct driver depends
on which branch is the "local" (%A) side:
| Situation | %A (local) |
%B (remote) |
Driver to use |
|---|---|---|---|
| Forgejo "Merge commit" button | main |
PR branch | ifcmerge_ours (--prioritise-local) |
Developer rebasing PR from main |
PR branch | main |
ifcmerge (default) |
For Forgejo server-side merges, use the "Merge commit" strategy (not
rebase or squash) and configure .gitattributes to use ifcmerge_ours:
*.ifc merge=ifcmerge_ours
ifcmerge (no flag) is for client-side use by developers updating their
working branch from main, where main arrives as the remote (%B) side
and its IDs are preserved by default.
Client-side .gitattributes
For client-side merges (git merge on a developer's machine) committed
.gitattributes files in the repository work fine. It is still worth
adding one:
*.ifc merge=ifcmerge
This ensures developers with ifcmerge installed get automatic IFC merges
locally, and tools that read gitattributes (e.g. diff viewers) can
identify .ifc files correctly.
Upgrading Forgejo
Custom assets (viewer.html, ifcurl.js, etc.) and footer.tmpl are
unaffected by Forgejo upstream upgrades — redeploy them after each asset
change and restart Forgejo once after updating footer.tmpl.