Use Online 3D Viewer for CAD files preview #14342

Closed
opened 2025-11-02 11:10:21 -06:00 by GiteaMirror · 5 comments
Owner

Originally created by @pevadev on GitHub (Apr 6, 2025).

Feature Description

This feature supports 3D preview for all of these file formats:
'3dm', '3ds', '3mf', 'amf', 'bim', 'brep', 'dae', 'fbx', 'fcstd', 'glb', 'gltf', 'ifc', 'igs', 'iges', 'stp', 'step', 'stl', 'obj', 'off', 'ply', 'wrl'

Intro

Hello everyone, I recently tried to implement the STL preview as it is described in docs.
The first problem i discovered was missing JQuery that needed to be loaded.
But then I wanted to add preview for other files and so I dug deeper.
I discovered an issue #5979 and this wonderful proposal from sapk to use Online 3D Viewer.
And so, I got to work.

My proposal

I think it would be great to implement this feature in docs as it is more versatile.
I tested it on PC and Android with all the supported files (the only one that didnt work was ".glb (v1)", v2 works fine).

The final implementation

Add template

In $GITEA_CUSTOM we need to add our template. This template should be saved in "$GITEA_CUSTOM/templates/custom/". Here create file "footer.tmpl" and add following text into it:
<!-- Load jQuery -->
<script src="/assets/scripts/jquery-3.6.0.min.js"></script>

<script>
  $(document).ready(function () {
    // Select links that end with any of the 3D file types
    const fileTypes = ['3dm', '3ds', '3mf', 'amf', 'bim', 'brep', 'dae', 'fbx', 'fcstd', 'glb', 'gltf', 'ifc', 'igs', 'iges', 'stp', 'step', 'stl', 'obj', 'off', 'ply', 'wrl'];
    const $3dLink = $('a.ui.mini.basic.button').filter(function () {
        const href = this.href.toLowerCase();
        return href.includes('/raw/') && fileTypes.some(ext => href.endsWith(`.${ext}`));
    });

    if ($3dLink.length) {
        var script = document.createElement('script');
        script.onload = function () {
            const fileUrl = $3dLink.attr("href");

            // Prepare the container for the viewer
            $(".file-view")
                .attr("id", "view-3d")
                .css({ padding: 0, margin: 0, height: "400px", width: "100%"})
                .empty();

            // get the parent element of the viewer
            let parentDiv = document.getElementById ('view-3d');

            // initialize the viewer with the parent element and some parameters
            let viewer = new OV.EmbeddedViewer (parentDiv, {
                backgroundColor : new OV.RGBAColor (59, 68, 76, 0),         // Transparent
                defaultColor : new OV.RGBColor (200, 200, 200),
                edgeSettings : new OV.EdgeSettings (false, new OV.RGBColor (0, 0, 0), 1),
                environmentSettings : new OV.EnvironmentSettings (
                    [
                        '/assets/o3dv/envmaps/fishermans_bastion/negx.jpg',
                        '/assets/o3dv/envmaps/fishermans_bastion/posx.jpg',
                        '/assets/o3dv/envmaps/fishermans_bastion/posy.jpg',
                        '/assets/o3dv/envmaps/fishermans_bastion/negy.jpg',
                        '/assets/o3dv/envmaps/fishermans_bastion/posz.jpg',
                        '/assets/o3dv/envmaps/fishermans_bastion/negz.jpg'
                    ],
                    false
                )
            });

            // load a model providing model urls
            viewer.LoadModelFromUrlList ([fileUrl]);
        };
        script.src = "/assets/o3dv/o3dv.min.js";

        document.head.appendChild(script);
    }
});  

console.log($("#view-3d").width(), $("#view-3d").height());
console.log(!!window.WebGLRenderingContext && !!document.createElement('canvas').getContext('webgl'));

</script>

Add public files

First, we need to add our JQuery script. This script will be saved in "$GITEA_CUSTOM/public/assets/scripts/". Here use e.g. wget to download the file.
wget https://code.jquery.com/jquery-3.6.0.min.js

Now we need to download latest version of O3DV. Go to "$GITEA_CUSTOM/public/assets/".
Create folder using (and cd into it):

mkdir o3dv
cd o3dv

Copy latest release zip link from GitHub (v0.15.0 as of now).
We can again use wget to download the file:

wget https://github.com/kovacsv/Online3DViewer/releases/download/0.15.0/o3dv.zip

Use e.g. unzip to unzip the archive:

unzip o3dv.zip

Folder permissions

Now the last thing. Change permissions on the "footer.tmpl":
chown git:git $GITEA_CUSTOM/templates/custom/footer.tmpl
chmod 770 $GITEA_CUSTOM/templates/custom/footer.tmpl

And on the public folder:

chown -R git:git $GITEA_CUSTOM/public

Now we have everything ready! Restart you gitea instance to apply these changes and you can test it in your browser.

The final words

If I missed something or you would like to know more, please leave a comment. I would be very glad if this would get changed in docs or even implemented natively.

Gitea info

As of now, I am running on v1.23.4.

Screenshots

Image

Image

Image

No response

Originally created by @pevadev on GitHub (Apr 6, 2025). ### Feature Description This feature supports 3D preview for all of these file formats: '3dm', '3ds', '3mf', 'amf', 'bim', 'brep', 'dae', 'fbx', 'fcstd', 'glb', 'gltf', 'ifc', 'igs', 'iges', 'stp', 'step', 'stl', 'obj', 'off', 'ply', 'wrl' <h2>Intro</h2> Hello everyone, I recently tried to implement the STL preview as it is described in docs. The first problem i discovered was missing JQuery that needed to be loaded. But then I wanted to add preview for other files and so I dug deeper. I discovered an issue #5979 and this wonderful proposal from [sapk](https://github.com/go-gitea/gitea/issues/5979#issuecomment-514797946) to use Online 3D Viewer. And so, I got to work. <h2>My proposal</h2> I think it would be great to implement this feature in docs as it is more versatile. I tested it on PC and Android with all the supported files (the only one that didnt work was ".glb (v1)", v2 works fine). <h2>The final implementation</h2> <h3>Add template</h3> In $GITEA_CUSTOM we need to add our template. This template should be saved in "$GITEA_CUSTOM/templates/custom/". Here create file "footer.tmpl" and add following text into it: ``` <!-- Load jQuery --> <script src="/assets/scripts/jquery-3.6.0.min.js"></script> <script> $(document).ready(function () { // Select links that end with any of the 3D file types const fileTypes = ['3dm', '3ds', '3mf', 'amf', 'bim', 'brep', 'dae', 'fbx', 'fcstd', 'glb', 'gltf', 'ifc', 'igs', 'iges', 'stp', 'step', 'stl', 'obj', 'off', 'ply', 'wrl']; const $3dLink = $('a.ui.mini.basic.button').filter(function () { const href = this.href.toLowerCase(); return href.includes('/raw/') && fileTypes.some(ext => href.endsWith(`.${ext}`)); }); if ($3dLink.length) { var script = document.createElement('script'); script.onload = function () { const fileUrl = $3dLink.attr("href"); // Prepare the container for the viewer $(".file-view") .attr("id", "view-3d") .css({ padding: 0, margin: 0, height: "400px", width: "100%"}) .empty(); // get the parent element of the viewer let parentDiv = document.getElementById ('view-3d'); // initialize the viewer with the parent element and some parameters let viewer = new OV.EmbeddedViewer (parentDiv, { backgroundColor : new OV.RGBAColor (59, 68, 76, 0), // Transparent defaultColor : new OV.RGBColor (200, 200, 200), edgeSettings : new OV.EdgeSettings (false, new OV.RGBColor (0, 0, 0), 1), environmentSettings : new OV.EnvironmentSettings ( [ '/assets/o3dv/envmaps/fishermans_bastion/negx.jpg', '/assets/o3dv/envmaps/fishermans_bastion/posx.jpg', '/assets/o3dv/envmaps/fishermans_bastion/posy.jpg', '/assets/o3dv/envmaps/fishermans_bastion/negy.jpg', '/assets/o3dv/envmaps/fishermans_bastion/posz.jpg', '/assets/o3dv/envmaps/fishermans_bastion/negz.jpg' ], false ) }); // load a model providing model urls viewer.LoadModelFromUrlList ([fileUrl]); }; script.src = "/assets/o3dv/o3dv.min.js"; document.head.appendChild(script); } }); console.log($("#view-3d").width(), $("#view-3d").height()); console.log(!!window.WebGLRenderingContext && !!document.createElement('canvas').getContext('webgl')); </script> ``` <h3>Add public files</h3> First, we need to add our JQuery script. This script will be saved in "$GITEA_CUSTOM/public/assets/scripts/". Here use e.g. wget to download the file. ``` wget https://code.jquery.com/jquery-3.6.0.min.js ``` Now we need to download latest version of O3DV. Go to "$GITEA_CUSTOM/public/assets/". Create folder using (and cd into it): ``` mkdir o3dv cd o3dv ``` Copy latest release zip link from [GitHub](https://github.com/kovacsv/Online3DViewer/releases) (v0.15.0 as of now). We can again use wget to download the file: ``` wget https://github.com/kovacsv/Online3DViewer/releases/download/0.15.0/o3dv.zip ``` Use e.g. unzip to unzip the archive: ``` unzip o3dv.zip ``` <h3>Folder permissions</h3> Now the last thing. Change permissions on the "footer.tmpl": ``` chown git:git $GITEA_CUSTOM/templates/custom/footer.tmpl chmod 770 $GITEA_CUSTOM/templates/custom/footer.tmpl ``` And on the public folder: ``` chown -R git:git $GITEA_CUSTOM/public ``` Now we have everything ready! Restart you gitea instance to apply these changes and you can test it in your browser. <h3>The final words</h3> If I missed something or you would like to know more, please leave a comment. I would be very glad if this would get changed in docs or even implemented natively. <h2>Gitea info</h2> As of now, I am running on v1.23.4. ### Screenshots ![Image](https://github.com/user-attachments/assets/304a1e35-7077-4bc0-84a4-440cb14c8ad3) ![Image](https://github.com/user-attachments/assets/8cd400d5-48ef-4e64-b398-8c225374939e) ![Image](https://github.com/user-attachments/assets/84fa21a8-8936-4ba5-875f-e2df1467ed92) _No response_
GiteaMirror added the type/proposal label 2025-11-02 11:10:21 -06:00
Author
Owner

@KN4CK3R commented on GitHub (Apr 7, 2025):

Now create a documentation pull request with your text. 👍

@KN4CK3R commented on GitHub (Apr 7, 2025): Now create a documentation pull request with your text. 👍
Author
Owner

@lunny commented on GitHub (Apr 7, 2025):

Thank you for your proposal. The jquery will be removed in the future version of Gitea. I think we should not include jquery here.

@lunny commented on GitHub (Apr 7, 2025): Thank you for your proposal. The jquery will be removed in the future version of Gitea. I think we should not include jquery here.
Author
Owner

@pevadev commented on GitHub (Apr 7, 2025):

Hey, thanks for feedback!

Now create a documentation pull request with your text. 👍

I´ve not seen the docs source, so this might take me a while.

Thank you for your proposal. The jquery will be removed in the future version of Gitea. I think we should not include jquery here.

I converted the script to JS and tested it on both PC and Android (works like a charm) :D

<script>
    document.addEventListener('DOMContentLoaded', () => {
      // Supported 3D file types
      const fileTypes = ['3dm', '3ds', '3mf', 'amf', 'bim', 'brep', 'dae', 'fbx', 'fcstd', 'glb', 'gltf', 'ifc', 'igs', 'iges', 'step', 'stl', 'obj', 'off', 'ply', 'wrl'];
  
      // Select matching link
      const links = Array.from(document.querySelectorAll('a.ui.mini.basic.button'));
      const link3D = links.find(link => {
        const href = link.href.toLowerCase();
        return href.includes('/raw/') && fileTypes.some(ext => href.endsWith(`.${ext}`));
      });
  
      if (link3D) {
        const script = document.createElement('script');
        script.onload = () => {
          const fileUrl = link3D.getAttribute('href');
  
          // Prepare the container for the viewer
          const fileView = document.querySelector('.file-view');
          if (fileView) {
            fileView.setAttribute('id', 'view-3d');
            fileView.style.padding = '0';
            fileView.style.margin = '0';
            fileView.style.height = '400px';
            fileView.style.width = '100%';
            fileView.innerHTML = '';
          }
  
          // Initialize viewer
          const parentDiv = document.getElementById('view-3d');
          if (parentDiv) {
            const viewer = new OV.EmbeddedViewer(parentDiv, {
              backgroundColor: new OV.RGBAColor(59, 68, 76, 0), // Transparent
              defaultColor: new OV.RGBColor(200, 200, 200),
              edgeSettings: new OV.EdgeSettings(false, new OV.RGBColor(0, 0, 0), 1),
              environmentSettings: new OV.EnvironmentSettings([
                '/assets/o3dv/envmaps/fishermans_bastion/negx.jpg',
                '/assets/o3dv/envmaps/fishermans_bastion/posx.jpg',
                '/assets/o3dv/envmaps/fishermans_bastion/posy.jpg',
                '/assets/o3dv/envmaps/fishermans_bastion/negy.jpg',
                '/assets/o3dv/envmaps/fishermans_bastion/posz.jpg',
                '/assets/o3dv/envmaps/fishermans_bastion/negz.jpg'
              ], false)
            });
  
            // Load the model
            viewer.LoadModelFromUrlList([fileUrl]);
          }
        };
  
        script.src = '/assets/o3dv/o3dv.min.js';
        document.head.appendChild(script);
      }
    });
</script>
@pevadev commented on GitHub (Apr 7, 2025): Hey, thanks for feedback! > Now create a documentation pull request with your text. 👍 I´ve not seen the docs source, so this might take me a while. > Thank you for your proposal. The jquery will be removed in the future version of Gitea. I think we should not include jquery here. I converted the script to JS and tested it on both PC and Android (works like a charm) :D ``` <script> document.addEventListener('DOMContentLoaded', () => { // Supported 3D file types const fileTypes = ['3dm', '3ds', '3mf', 'amf', 'bim', 'brep', 'dae', 'fbx', 'fcstd', 'glb', 'gltf', 'ifc', 'igs', 'iges', 'step', 'stl', 'obj', 'off', 'ply', 'wrl']; // Select matching link const links = Array.from(document.querySelectorAll('a.ui.mini.basic.button')); const link3D = links.find(link => { const href = link.href.toLowerCase(); return href.includes('/raw/') && fileTypes.some(ext => href.endsWith(`.${ext}`)); }); if (link3D) { const script = document.createElement('script'); script.onload = () => { const fileUrl = link3D.getAttribute('href'); // Prepare the container for the viewer const fileView = document.querySelector('.file-view'); if (fileView) { fileView.setAttribute('id', 'view-3d'); fileView.style.padding = '0'; fileView.style.margin = '0'; fileView.style.height = '400px'; fileView.style.width = '100%'; fileView.innerHTML = ''; } // Initialize viewer const parentDiv = document.getElementById('view-3d'); if (parentDiv) { const viewer = new OV.EmbeddedViewer(parentDiv, { backgroundColor: new OV.RGBAColor(59, 68, 76, 0), // Transparent defaultColor: new OV.RGBColor(200, 200, 200), edgeSettings: new OV.EdgeSettings(false, new OV.RGBColor(0, 0, 0), 1), environmentSettings: new OV.EnvironmentSettings([ '/assets/o3dv/envmaps/fishermans_bastion/negx.jpg', '/assets/o3dv/envmaps/fishermans_bastion/posx.jpg', '/assets/o3dv/envmaps/fishermans_bastion/posy.jpg', '/assets/o3dv/envmaps/fishermans_bastion/negy.jpg', '/assets/o3dv/envmaps/fishermans_bastion/posz.jpg', '/assets/o3dv/envmaps/fishermans_bastion/negz.jpg' ], false) }); // Load the model viewer.LoadModelFromUrlList([fileUrl]); } }; script.src = '/assets/o3dv/o3dv.min.js'; document.head.appendChild(script); } }); </script> ```
Author
Owner

@pevadev commented on GitHub (Apr 7, 2025):

Ok, I added a pull request to the docs.

@pevadev commented on GitHub (Apr 7, 2025): Ok, I added a pull request to the docs.
Author
Owner

@lunny commented on GitHub (Apr 7, 2025):

ref: https://gitea.com/gitea/docs/pulls/199

@lunny commented on GitHub (Apr 7, 2025): ref: https://gitea.com/gitea/docs/pulls/199
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/gitea#14342