From aa6c4027777985b8198b7881cd3abc5df8f48a88 Mon Sep 17 00:00:00 2001
From: mie <79989386+mahach666@users.noreply.github.com>
Date: Wed, 11 Nov 2026 14:45:48 +0300
Subject: [PATCH] chore: align repository with IOExtend standards
Bring documentation, CI and project settings in line with RvtIO.
- Generate the XML documentation file for the IOViewer package; the
IsPackable condition in Directory.Build.props never matched.
- Run the release workflow only for version tags, fail on gh errors and
stop overwriting assets of an existing release.
- Fail pack-release.ps1 when the source archive cannot be created.
- Remove claims of .mtl and mesh simplification support from the docs.
- Add the Autodesk trademark notice and use mahach666 as the copyright
holder everywhere.
- Describe supported versions, security scope, development setup and
the clean-room policy in SECURITY.md and CONTRIBUTING.md.
- Run tests on .NET 8 and .NET 10; pin SDK 10.0.100 without prerelease.
- Add NuGet audit, Dependabot, .gitattributes and issue/PR templates.
---
.gitattributes | 13 +++
.github/ISSUE_TEMPLATE/bug_report.md | 19 +++++
.github/ISSUE_TEMPLATE/feature_request.md | 11 +++
.github/PULL_REQUEST_TEMPLATE.md | 8 ++
.github/dependabot.yml | 10 +++
.github/workflows/ci.yml | 14 ++--
.github/workflows/docs.yml | 15 ++--
.github/workflows/release.yml | 28 ++-----
CHANGELOG.md | 19 ++++-
CONTRIBUTING.md | 96 +++++++++++++++++-----
Directory.Build.props | 12 ++-
LICENSE | 2 +-
README.md | 9 +-
SECURITY.md | 31 +++++--
docs/index.md | 4 +-
docs/public-api.md | 2 +-
global.json | 5 +-
src/IOViewer/IOViewer.csproj | 1 +
tests/IOViewer.Tests/IOViewer.Tests.csproj | 2 +-
tools/pack-release.ps1 | 3 +-
20 files changed, 230 insertions(+), 74 deletions(-)
create mode 100644 .gitattributes
create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md
create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
create mode 100644 .github/dependabot.yml
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..f7d3cd9
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,13 @@
+# Source and text files are stored and checked out with LF.
+* text=auto eol=lf
+
+# Fixtures and images are never normalised.
+*.glb binary
+*.gz binary
+*.png binary
+*.jpg binary
+*.jpeg binary
+*.gif binary
+*.ico binary
+*.nupkg binary
+*.snupkg binary
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..2ea413f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,19 @@
+---
+name: Bug report
+about: A model is imported or displayed wrongly, or the tool fails
+labels: bug
+---
+
+**IOViewer version** (`ioviewer --version` or the package version):
+
+**Input format** (`.glb`, `.obj`, `.json` or a `ViewerDocument` built in code):
+
+**Browser and operating system** (for problems in the generated viewer):
+
+**Command line or API call** (remove confidential values and personal paths):
+
+**What you expected**:
+
+**What happened** (error messages, diagnostics from standard error, browser console errors):
+
+Please do not attach models with confidential content. A short description of the model is enough to start.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..59d2609
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,11 @@
+---
+name: Feature request
+about: Suggest an improvement
+labels: enhancement
+---
+
+**What do you want to do?**
+
+**What happens today?**
+
+**Which input formats or viewer features does it concern?**
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..47541a9
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,8 @@
+## What changes and why
+
+## How it was checked
+
+- [ ] `dotnet build IOViewer.slnx -c Release` has no warnings
+- [ ] `dotnet test IOViewer.slnx -c Release` passes
+- [ ] Generated HTML and JSON for the same inputs are unchanged, or the differences are listed and intended
+- [ ] No customer models, personal data, vendor code or third-party JavaScript is added
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..a846233
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: nuget
+ directory: /
+ schedule:
+ interval: weekly
+ - package-ecosystem: github-actions
+ directory: /
+ schedule:
+ interval: weekly
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a44c497..cb23daf 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -16,17 +16,17 @@ jobs:
os: [windows-latest]
runs-on: ${{ matrix.os }}
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-dotnet@v4
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
with:
+ global-json-file: global.json
dotnet-version: |
8.0.x
- 10.0.x
- run: dotnet restore IOViewer.slnx
- run: dotnet build IOViewer.slnx -c Release --no-restore
- run: dotnet test IOViewer.slnx -c Release --no-build
- run: dotnet pack IOViewer.slnx -c Release --no-build -o artifacts
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@v7
with:
name: packages-${{ matrix.os }}
path: artifacts/*.nupkg
@@ -35,10 +35,10 @@ jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-dotnet@v4
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
with:
+ global-json-file: global.json
dotnet-version: |
8.0.x
- 10.0.x
- run: dotnet build src/IOViewer.Cli/IOViewer.Cli.csproj -c Release
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 54ffb45..df55576 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -29,16 +29,15 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-dotnet@v4
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
with:
- dotnet-version: |
- 8.0.x
- 10.0.x
+ global-json-file: global.json
- run: dotnet tool restore
- run: dotnet docfx docfx.json --warningsAsErrors
- - run: rm -f _site/manifest.json
- - uses: actions/upload-pages-artifact@v4
+ # manifest.json records the build machine paths and is not part of the site.
+ - run: rm _site/manifest.json
+ - uses: actions/upload-pages-artifact@v5
with:
path: _site
@@ -54,4 +53,4 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
- uses: actions/deploy-pages@v4
+ uses: actions/deploy-pages@v5
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 55b1b87..df37d82 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -3,7 +3,6 @@ name: Release
on:
push:
tags: ['v*']
- workflow_dispatch:
permissions:
contents: write
@@ -13,9 +12,10 @@ jobs:
publish:
runs-on: windows-latest
steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-dotnet@v4
+ - uses: actions/checkout@v7
+ - uses: actions/setup-dotnet@v6
with:
+ global-json-file: global.json
dotnet-version: |
8.0.x
10.0.x
@@ -24,7 +24,7 @@ jobs:
run: |
$version = dotnet msbuild src/IOViewer/IOViewer.csproj -getProperty:Version -nologo
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- if ($env:GITHUB_REF_NAME -and $env:GITHUB_REF_NAME.StartsWith("v") -and $env:GITHUB_REF_NAME -cne "v$($version.Trim())") {
+ if ($env:GITHUB_REF_NAME -cne "v$($version.Trim())") {
throw "The release tag must match the package version v$($version.Trim())."
}
- run: dotnet restore IOViewer.slnx
@@ -33,16 +33,16 @@ jobs:
- name: Pack release
shell: pwsh
run: ./tools/pack-release.ps1
- - uses: actions/upload-artifact@v4
+ - uses: actions/upload-artifact@v7
with:
name: packages
path: artifacts/*
- - name: Create or update release
+ - name: Create release
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
- $version = if ($env:GITHUB_REF_NAME -and $env:GITHUB_REF_NAME.StartsWith("v")) { $env:GITHUB_REF_NAME.Substring(1) } else { (dotnet msbuild src/IOViewer/IOViewer.csproj -getProperty:Version -nologo).Trim() }
+ $version = $env:GITHUB_REF_NAME.Substring(1)
$changelog = Get-Content -LiteralPath CHANGELOG.md -Encoding utf8
$start = [array]::FindIndex($changelog, [Predicate[string]] { param($line) $line.StartsWith("## [$version]") })
if ($start -lt 0) { throw "CHANGELOG.md has no entry for $version" }
@@ -50,18 +50,8 @@ jobs:
for ($i = $start + 1; $i -lt $changelog.Count -and -not $changelog[$i].StartsWith('## ['); $i++) { $notes += $changelog[$i] }
$notes | Set-Content -LiteralPath release-notes.md -Encoding utf8
$files = @(Get-ChildItem artifacts -File | ForEach-Object { $_.FullName })
- $tagName = if ($env:GITHUB_REF_NAME -and $env:GITHUB_REF_NAME.StartsWith("v")) { $env:GITHUB_REF_NAME } else { "v$version" }
-
- # Check if release exists
- $exists = gh release view $tagName 2>&1
- if ($LASTEXITCODE -eq 0) {
- Write-Host "Updating existing release $tagName..."
- gh release edit $tagName --notes-file release-notes.md
- gh release upload $tagName @files --clobber
- } else {
- Write-Host "Creating release $tagName..."
- gh release create $tagName @files --title "IOViewer v$version" --notes-file release-notes.md
- }
+ gh release create $env:GITHUB_REF_NAME --title $env:GITHUB_REF_NAME --notes-file release-notes.md @files
+ if ($LASTEXITCODE -ne 0) { throw "gh release create failed with exit code $LASTEXITCODE" }
# Trusted publishing: the NuGet policy for this repository and workflow file exchanges the GitHub OIDC token for a short-lived key.
- uses: NuGet/login@v1
id: nuget-login
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d7f0137..462897a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,23 @@
# Changelog
-All notable changes to the `IOViewer` library and CLI are documented in this file.
+All notable changes are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
+and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html); versions before 1.0 may change the
+API between minor releases.
+
+## [Unreleased]
+
+### Fixed
+- The `IOViewer` package now includes the XML documentation file, so existing API comments show in IntelliSense.
+- The release workflow runs only for version tags again, fails on any `gh release` error and no longer overwrites assets of an existing release.
+- `tools/pack-release.ps1` fails when creating the source archive fails.
+- Documentation no longer claims `.mtl` material support or mesh simplification, neither of which exists.
+
+### Changed
+- Tests run on both .NET 8 and .NET 10.
+- `global.json`, CI workflows and repository settings follow the shared IOExtend conventions: SDK 10.0.100 without prerelease, NuGet vulnerability audit, Dependabot, LF line endings, issue and pull request templates.
+- Copyright holder is `mahach666` in the license, package metadata and README.
+- README and documentation state that IOViewer is not affiliated with Autodesk.
+- `SECURITY.md` and `CONTRIBUTING.md` describe supported versions, security scope, development setup and the clean-room policy.
## [0.1.0] - 2026-11-11
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 77e95fa..4c2fb99 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,31 +1,89 @@
# Contributing to IOViewer
-## Reporting Bugs
+## Reporting bugs
Open a [GitHub issue](https://github.com/IOExtend/IOViewer/issues) with:
-- The `IOViewer` / `ioviewer` version.
-- The command line or C# API call used, with confidential or personal paths removed.
-- A minimal description of how to reproduce the issue.
-- Expected and actual results, including relevant error messages or stack traces.
-Do not attach proprietary models if they contain confidential or customer data.
+- The IOViewer version (`ioviewer --version` or the package version).
+- The command line or API call used, with confidential values and personal paths removed.
+- A minimal description of how to reproduce the problem.
+- Expected and actual results, including relevant error messages.
-Report security vulnerabilities privately through the **Security** tab.
+Do not attach models if they contain confidential or customer data.
+A minimal description is better than sharing a confidential model.
-## Code Conventions & Clean-Room Policy
+Report security issues through GitHub private vulnerability reporting in
+the Security tab. Do not open public issues for security vulnerabilities.
-- **Clean-Room Development**: All code must be independently authored without decompiled proprietary source code, proprietary headers, or vendor SDKs.
-- Do not commit proprietary project data or third-party binaries to the repository.
-- Keep nullable reference types enabled (`enable`).
-- Warnings are treated as errors (`true`).
-- Zero native or third-party library dependencies for core HTML generation and exporting functionality.
+## Proposing changes
-## Releases & NuGet Publishing
+Open an issue first for larger changes so the scope and approach can be
+discussed before implementation. Keep changes focused on the agreed problem.
-Push a tag matching the package version, such as `v0.1.0`, to trigger the `release.yml` workflow.
-The workflow builds and tests the solution, packs release packages and symbols, generates archives with checksums, publishes the GitHub Release, and publishes packages to NuGet.org via Trusted Publishing (GitHub Actions OIDC).
-The NuGet policy on NuGet.org must name this repository (`IOExtend/IOViewer`), workflow `release.yml`, publisher `GitHubActions`, package pattern `IOViewer*`, and owner `mahach`.
+## Development setup
-## Licensing Contributions
+Install the .NET SDK specified by `global.json`. It currently specifies
+10.0.100, allows roll-forward to the latest feature band, and excludes
+prerelease SDKs. Tests run on .NET 8 and .NET 10, so both runtimes are needed.
-All contributions are licensed under the [MIT License](LICENSE). By submitting a pull request, you confirm that you have the right to contribute your code under that license.
+From the repository root, run:
+
+```sh
+dotnet build IOViewer.slnx -c Release
+dotnet test IOViewer.slnx -c Release
+```
+
+The library is in `src/IOViewer`, the CLI in `src/IOViewer.Cli`, and tests in
+`tests/IOViewer.Tests`. Tests use small synthetic models built in code.
+The repository ships no customer models.
+
+## Clean-room policy
+
+- Write all code independently. Do not use decompiled or leaked source code,
+ proprietary headers, vendor SDKs or code copied from other viewers.
+- Do not add third-party JavaScript to the generated HTML. The viewer runs on
+ plain WebGL and must stay self-contained and offline.
+- Do not add customer models, confidential data, vendor files or binaries to
+ the repository. Keep private test files outside version control.
+- Do not put personal data in code, documentation, test data or commit
+ metadata. Use your GitHub noreply address as the commit email.
+
+## Code conventions
+
+- Follow the surrounding code and repository formatting settings.
+- Keep nullable reference types enabled.
+- Warnings are treated as errors.
+- Write short English comments that explain why.
+- Document new and changed public APIs with XML documentation comments.
+- Do not write console output from the library. Only the CLI writes to the
+ console, with diagnostics on standard error.
+- Do not add runtime dependencies to the library without discussing it first.
+
+## Pull requests
+
+Include:
+
+- A description of the problem and the change.
+- Tests for behavior changes, including relevant errors and edge cases.
+- The build and test commands run, their results, and any skipped checks.
+- A note on how the generated HTML changes when the viewer template is affected.
+
+Write commit messages in the imperative mood, for example,
+"Fix section box clipping on rotated models".
+
+## Releases
+
+Push a tag matching the package version, such as `v0.2.0`, to run `release.yml`.
+The workflow builds and tests the solution, attaches packages, symbols, source and checksums to a GitHub release,
+and publishes the NuGet packages through Trusted Publishing. The release notes are the section of `CHANGELOG.md` for the version, so add that section before the tag.
+The NuGet policy must name this repository, `release.yml`, the configured NuGet profile and the `IOViewer*` package pattern.
+
+## Licensing contributions
+
+Contributions are licensed under the MIT license. By submitting a
+contribution, you confirm that you have the right to contribute it under
+that license.
+
+## Questions
+
+Ask questions in GitHub Discussions or repository issues.
diff --git a/Directory.Build.props b/Directory.Build.props
index 22c6122..a543d01 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -16,7 +16,7 @@
0.1.0
mahach666
- Copyright (c) 2026 IOExtend
+ Copyright (c) 2026 mahach666
IOViewer
Fast, pure managed .NET library and CLI tool for generating standalone, zero-dependency interactive 3D WebGL/HTML BIM & CAD model viewers.
en
@@ -24,7 +24,7 @@
https://github.com/IOExtend/IOViewer
https://github.com/IOExtend/IOViewer
git
- bim;cad;webgl;html-viewer;3d-viewer;threejs;revit;ifc;navisworks;gltf;glb;obj;timeliner;4d;viewcube;section-box;measure;grids
+ bim;cad;webgl;html-viewer;3d-viewer;revit;ifc;navisworks;gltf;glb;obj;timeliner;4d;viewcube;section-box;measure;grids
README.md
icon.png
@@ -35,13 +35,19 @@
- true
$(NoWarn);CS1591
true
true
latest-recommended
+
+
+ true
+ all
+ low
+
+
true
diff --git a/LICENSE b/LICENSE
index adefd9a..a79c677 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2026 IOViewer contributors
+Copyright (c) 2026 mahach666
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 8fc9822..0ec0eef 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
[](https://opensource.org/licenses/MIT)
[](https://dotnet.microsoft.com/)
-IOViewer is a fast, 100% managed .NET library and command line tool that generates standalone, zero-dependency interactive 3D WebGL / HTML BIM & CAD model viewers from code, glTF/GLB, Wavefront OBJ, JSON, or sibling libraries ([RvtIO](https://github.com/IOExtend/RvtIO), [IfcIO](https://github.com/IOExtend/IfcIO), and [NwcIO](https://github.com/IOExtend/NwcIO)).
+IOViewer is a fast, 100% managed .NET library and command line tool that generates standalone, zero-dependency interactive 3D WebGL / HTML BIM & CAD model viewers from code, glTF/GLB, Wavefront OBJ, or JSON. Geometry read by sibling libraries ([RvtIO](https://github.com/IOExtend/RvtIO), [IfcIO](https://github.com/IOExtend/IfcIO), and [NwcIO](https://github.com/IOExtend/NwcIO)) can be passed in by building a `ViewerDocument` in code; IOViewer has no direct dependency on them.
The generated HTML file is completely self-contained, offline-ready, and works in any modern browser without external servers or cloud dependencies.
@@ -128,11 +128,12 @@ The documentation site with API references and guides is at
true
IOViewer
+ true
diff --git a/tests/IOViewer.Tests/IOViewer.Tests.csproj b/tests/IOViewer.Tests/IOViewer.Tests.csproj
index becdb51..f98dd62 100644
--- a/tests/IOViewer.Tests/IOViewer.Tests.csproj
+++ b/tests/IOViewer.Tests/IOViewer.Tests.csproj
@@ -1,7 +1,7 @@
- net10.0
+ net8.0;net10.0
false
$(NoWarn);CA1707
diff --git a/tools/pack-release.ps1 b/tools/pack-release.ps1
index 94e4a61..669fd36 100644
--- a/tools/pack-release.ps1
+++ b/tools/pack-release.ps1
@@ -65,7 +65,8 @@ New-Zip $cliNet10 (Join-Path $Output "IOViewer-Cli-$version-net10.0.zip")
Write-Host "Archiving repository source tree..."
$sourceZip = Join-Path $Output "IOViewer-$version-source.zip"
if (Test-Path -LiteralPath $sourceZip) { Remove-Item -LiteralPath $sourceZip }
-git archive --format=zip --prefix="IOViewer-$version/" HEAD -o $sourceZip
+& git -C $root archive --format=zip --prefix="IOViewer-$version/" --output=$sourceZip HEAD
+if ($LASTEXITCODE -ne 0) { throw "git archive failed with exit code $LASTEXITCODE" }
# 5. Pack NuGet Packages
Write-Host "Packing NuGet packages..."