ifcurl/PLAN.md
2026-04-22 08:31:24 +01:00

285 lines
9.1 KiB
Markdown

# IFC URL — Development Plan
## Overview
IFC URL requires work across four distinct areas:
1. A Python core library and CLI tool
2. A preview service with Gitea integration
3. Desktop app integration (Bonsai, IFC Viewer)
4. The federation extension to `IFCDOCUMENTREFERENCE`
The Python core is the foundation for all other work. The Gitea integration
and desktop app work can proceed in parallel once the core exists.
### Language ownership
| Component | Language | Rationale |
|---|---|---|
| URL parsing, git fetch, selector execution, rendering | Python | Built on IfcOpenShell |
| Bonsai plugin | Python | Bonsai is a Blender/Python addon |
| CLI tool | Python | Wraps the core library |
| Preview service | Python | Wraps the core library |
| Gitea plugin | Go | Gitea is written in Go; the plugin only calls an HTTP endpoint |
| Web viewer integration | JavaScript | Future, not in current scope |
The Python core is a strong candidate for eventual contribution to
IfcOpenShell, but this is not a prerequisite for any phase.
---
## Phase 1 — Python core and CLI tool
Build a Python library that resolves an `ifc://` URL and produces a rendered
PNG. This validates the spec against real IFC files and is the foundation for
all subsequent work.
### Library responsibilities
- Parse an `ifc://` URL into its components
- Infer git transport from URL structure (SSH, HTTPS, local)
- Fetch the IFC file from the repository at the specified ref
- Execute the IfcOpenShell selector against the loaded model
- Apply camera (perspective and orthographic), clipping planes, and
visibility mode
- Render a static PNG
### CLI interface
```bash
ifc-url render "ifc://example.com/org/repo@abc123?path=model.ifc&selector=IfcWall&fov=60"
ifc-url render "ifc://example.com/org/repo@heads/main?path=model.ifc&camera=0,0,8,0,0,-1,0,1,0&scale=50"
```
### Notes
- IfcOpenShell handles selector execution, model parsing, and geometry
- Rendering requires a headless approach; options include IfcOpenShell's own
geometry processing with a software or headless OpenGL renderer
- Git access uses the platform credential store for HTTPS and ssh-agent or
key files for SSH
- The CLI accepts the URL as a plain string so it can be called from
non-Python contexts
---
## Phase 2 — Preview service
Wrap the Phase 1 library in an HTTP service for use by Gitea and other
consumers.
### Endpoint
```
POST /preview
body: { url: "ifc://..." }
response: image/png
```
### Caching
| Tier | Cache key | Contents | Notes |
|---|---|---|---|
| 2 | commit hash | Parsed model structure | Shared across requests |
| 3 | commit hash + selector | Resolved GUID set | |
| 4 | full URL hash | Rendered PNG | Not applied to mutable refs |
Mutable refs (`@heads/`, `@HEAD`) must not be cached at tier 4 since the
underlying commit may change. Commit hash refs are immutable and can be
cached indefinitely at all tiers.
### Authentication
- **Co-located with Gitea** — uses the requesting user's Gitea session token,
passed from the Gitea plugin
- **Standalone** — sideloaded token configuration per git host
---
## Phase 3 — Gitea integration
Add `ifc://` link detection and preview embedding to Gitea.
### Go plugin responsibilities
- Detect `ifc://` links in post and comment content
- Call the preview service with the URL and the current user's session token
- Embed the returned PNG inline with a link that opens the URL
- Degrade gracefully when the preview service is unavailable (show the raw
URL rather than failing)
### Notes
- The plugin has no IFC awareness; all IFC logic lives in the preview service
- Repeated embeds of the same URL across different posts do not trigger
re-renders — the preview service cache handles deduplication
- The preview service may run as a companion process on the same host or
as a separately configured external service
---
## Phase 3b — Web IFC viewer
Add a 3D viewer that opens in a separate browser window when viewing an `.ifc`
file in Forgejo.
### Architecture
- **Forgejo Go patch**: when rendering the file view for a `.ifc` file, inject
a "View in 3D" button that opens
`http://localhost:8000/viewer?url=ifc://...` in a new tab. The ifc:// URL
encodes the current host, repo, ref, and file path.
- **`/viewer` endpoint** in the ifcurl preview service: returns a self-contained
HTML page. No server-side IFC processing — the browser does all rendering.
- **Browser rendering**: the viewer page loads `@thatopen/components` (and its
`web-ifc` + Three.js peer dependencies) from a CDN via an ES module importmap.
It constructs the Forgejo raw file URL from the ifc:// URL parameters and
fetches the IFC bytes directly from Forgejo.
### Current scope (Phase 3b)
- Display the full model for whatever ref is shown in Forgejo.
- Basic orbit/pan/zoom camera controls.
- No filtering or selection UI yet.
### Future scope
- Element filtering and selection using `@thatopen/components` classifier and
highlighter APIs.
- Camera state serialised to an `ifc://` URL so the user can copy a view link
(feeds into Phase 4 Bonsai "Copy view URL").
- Diff highlighting driven by ifcmerge output (see Phase 3c).
---
## Phase 3c — ifcmerge integration
`ifcmerge` is a git custom merge driver that resolves conflicts in `.ifc` files
that git's built-in 3-way merge cannot handle. Where two branches have both
modified an IFC file (a fork), git would report an unresolvable conflict;
ifcmerge performs a semantics-aware merge and produces a valid merged IFC file.
### Git merge driver configuration
Register ifcmerge as the git merge driver for `.ifc` files on the Forgejo
server:
```
# /etc/gitconfig or ~forgejo/.gitconfig
[merge "ifcmerge"]
name = IFC merge driver
driver = ifcmerge %O %A %B %L
```
```
# .gitattributes in each repo, or server-side gitattributes
*.ifc merge=ifcmerge
```
With this in place, Forgejo's existing "merge automatically" path will invoke
ifcmerge via git when merging `.ifc` files, and the PR merge button will work
without any Go-side changes for the common case.
### Forgejo integration
- Verify that Forgejo's merge-ability check (the "these branches can be merged
automatically" indicator) correctly reflects ifcmerge's ability to merge
`.ifc` files — investigate whether the check runs a trial merge via git or
uses a heuristic.
- If needed, patch Forgejo to run a trial `git merge --no-commit` to get an
accurate result for IFC files.
### 3D diff view (future)
- After a merge completes, surface a "View merge in 3D" button in the PR using
the Phase 3b viewer.
- Use `@thatopen/components` highlighter to colour added, removed, and modified
elements differently, driven by comparing the merged IFC against either parent.
---
## Phase 4 — Bonsai integration
Add `ifc://` handling to Bonsai.
### Protocol handler
Register `ifc://` as an OS protocol handler on installation (Windows,
macOS, Linux). On receiving a URL, resolve the git source, load the model,
and apply the view state from the URL parameters.
### "Copy view URL"
A button that generates an `ifc://` URL from the current Bonsai state:
- Git remote, ref, and file path of the open model
- Active selection converted to an IfcOpenShell selector
- Current camera converted to the `camera` + `fov` or `scale` format,
in IFC world coordinates
- Active clipping planes as `clip` parameters
- Current visibility mode
The button always generates a commit hash ref by default. Generating a
`@heads/` ref is a secondary option for authoring links intended to track
a branch.
### Federation
When opening a model via `ifc://`, Bonsai resolves `IFCDOCUMENTREFERENCE`
locations using the repo and ref from the root file's URL as context.
`ifc://` locations in linked model references are resolved recursively.
---
## Phase 5 — IFC Viewer integration
Equivalent to Phase 4 for the IFC Viewer desktop application.
---
## Phase 6 — Federation extension
Extend the `IFCDOCUMENTREFERENCE` location field in Bonsai to accept
`ifc://` URLs, enabling cross-repo and cross-server federation.
### Tasks
- When saving a linked model reference, offer the option to write the
location as an `ifc://` URL rather than a relative path
- When a relative path would traverse above the repository root, prompt
the user to convert it to an `ifc://` URL
- Resolve `ifc://` location fields through the Phase 4 URL resolver
The transformation matrix in `IFCDOCUMENTREFERENCE` is unaffected by this
change. Phase 4 must be complete before this phase begins.
---
## Future work
### BCF export
An additional preview service endpoint returning a BCF file:
```
POST /bcf
body: { url: "ifc://..." }
response: application/zip
```
Resolves the selector to a GUID set and constructs a BCF viewpoint from the
camera, clipping planes, and visibility state. No implementation is planned
before Phase 2 is complete.
### Web viewer integration
JavaScript integration with web-based IFC viewers (IFC.js, xeokit) and
browser-side forum embedding. Not in current scope.
### IfcOpenShell contribution
Once the Python core is stable, the URL parsing and resolution logic is a
candidate for contribution to IfcOpenShell as a shared utility. This is not
a prerequisite for any phase.