Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -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.
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -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?**
8 changes: 8 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: nuget
directory: /
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
14 changes: 7 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
15 changes: 7 additions & 8 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -54,4 +53,4 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
28 changes: 9 additions & 19 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ name: Release
on:
push:
tags: ['v*']
workflow_dispatch:

permissions:
contents: write
Expand All @@ -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
Expand All @@ -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
Expand All @@ -33,35 +33,25 @@ 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" }
$notes = @()
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
Expand Down
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
96 changes: 77 additions & 19 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -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 (`<Nullable>enable</Nullable>`).
- Warnings are treated as errors (`<TreatWarningsAsErrors>true</TreatWarningsAsErrors>`).
- 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.
12 changes: 9 additions & 3 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
<PropertyGroup>
<Version>0.1.0</Version>
<Authors>mahach666</Authors>
<Copyright>Copyright (c) 2026 IOExtend</Copyright>
<Copyright>Copyright (c) 2026 mahach666</Copyright>
<Product>IOViewer</Product>
<Description>Fast, pure managed .NET library and CLI tool for generating standalone, zero-dependency interactive 3D WebGL/HTML BIM &amp; CAD model viewers.</Description>
<NeutralLanguage>en</NeutralLanguage>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/IOExtend/IOViewer</PackageProjectUrl>
<RepositoryUrl>https://github.com/IOExtend/IOViewer</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageTags>bim;cad;webgl;html-viewer;3d-viewer;threejs;revit;ifc;navisworks;gltf;glb;obj;timeliner;4d;viewcube;section-box;measure;grids</PackageTags>
<PackageTags>bim;cad;webgl;html-viewer;3d-viewer;revit;ifc;navisworks;gltf;glb;obj;timeliner;4d;viewcube;section-box;measure;grids</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>
Expand All @@ -35,13 +35,19 @@
</ItemGroup>

<PropertyGroup Condition="'$(MSBuildProjectExtension)' == '.csproj'">
<GenerateDocumentationFile Condition="'$(IsPackable)' == 'true'">true</GenerateDocumentationFile>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<AnalysisLevel>latest-recommended</AnalysisLevel>
</PropertyGroup>

<!-- Report known-vulnerable packages, direct and transitive, as warnings (NU1901-NU1904). -->
<PropertyGroup>
<NuGetAudit>true</NuGetAudit>
<NuGetAuditMode>all</NuGetAuditMode>
<NuGetAuditLevel>low</NuGetAuditLevel>
</PropertyGroup>

<PropertyGroup Condition="'$(CI)' == 'true' Or '$(GITHUB_ACTIONS)' == 'true' Or '$(TF_BUILD)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading
Loading