Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
73659e4
Render 3d models into iframe
silverwind Apr 15, 2026
76b22d9
fine tune
wxiaoguang Apr 15, 2026
28ff9e5
fix comment
wxiaoguang Apr 15, 2026
2780dc4
Move 3D iframe rendering to frontend
silverwind Apr 15, 2026
2bd893e
Remove dash from viewer-3d naming
silverwind Apr 15, 2026
8eaf95c
Restore explicit edgeSettings
silverwind Apr 15, 2026
5ce09dd
Integrate 3D plugin with external-render framework
silverwind Apr 15, 2026
a234c1b
Revert to backend-rendered 3D viewer
silverwind Apr 15, 2026
dbf71b9
Merge branch 'main' into 3diframe
wxiaoguang Apr 16, 2026
a149a1c
refactor
wxiaoguang Apr 16, 2026
40f7a9b
lazy load
wxiaoguang Apr 16, 2026
72f2736
add comment
wxiaoguang Apr 16, 2026
5f18aba
Fix iframe content corruption and ref double-escape
silverwind Apr 16, 2026
cd9cc52
Surface plugin errors via console.error
silverwind Apr 16, 2026
2a99783
Add e2e regression test for asciicast on non-ASCII branch
silverwind Apr 16, 2026
49b0cb9
Merge branch 'main' into 3diframe
silverwind Apr 16, 2026
1c882f4
Remove obsolete test, covered by e2e
silverwind Apr 16, 2026
f259edd
Apply suggestion from @silverwind
silverwind Apr 16, 2026
b85c711
add comment and TODO
wxiaoguang Apr 17, 2026
7487d79
revert wrongly deleted comment
wxiaoguang Apr 17, 2026
78e11b3
add more comments
wxiaoguang Apr 17, 2026
23eb19b
Fix 3D viewer collapsed-iframe regression, expand e2e
silverwind Apr 17, 2026
42070d9
remove iframe window margin/padding
wxiaoguang Apr 17, 2026
c1e33ed
remove markup class for iframe render
wxiaoguang Apr 17, 2026
e6d8a45
Assert iframe/container height for asciicast and openapi e2e
silverwind Apr 17, 2026
9002c44
Fix TestRenderIFrame after data-global-init addition
silverwind Apr 17, 2026
80b3db8
fix sandboxed console error
wxiaoguang Apr 17, 2026
4499460
fix border radius
wxiaoguang Apr 17, 2026
7900812
Expand openapi e2e to exercise swagger-ui $ref resolver
silverwind Apr 17, 2026
1e44f97
fix lint
wxiaoguang Apr 17, 2026
00f73ec
Fix swagger pushState in srcdoc iframe, lint and quality cleanup
silverwind Apr 17, 2026
942292c
Revert arrow simplification in lazy plugin loaders
silverwind Apr 17, 2026
28bea73
Merge branch 'main' into 3diframe
silverwind Apr 17, 2026
95d1797
add comment
wxiaoguang Apr 17, 2026
782cb42
fix render query params
wxiaoguang Apr 17, 2026
adfa063
Merge branch 'main' into 3diframe
silverwind Apr 17, 2026
c1c7354
Add e2e assertions for renderer padding and 3D bgcolor
silverwind Apr 17, 2026
3372b59
Merge branch 'main' into 3diframe
GiteaBot Apr 17, 2026
81700d9
Avoid non-null assertions on boundingBox in assertFlushWithParent
silverwind Apr 17, 2026
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
1 change: 1 addition & 0 deletions modules/markup/external/external.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
// RegisterRenderers registers all supported third part renderers according settings
func RegisterRenderers() {
markup.RegisterRenderer(&openAPIRenderer{})
markup.RegisterRenderer(&viewer3dRenderer{})
for _, renderer := range setting.ExternalMarkupRenderers {
markup.RegisterRenderer(&Renderer{renderer})
}
Expand Down
79 changes: 79 additions & 0 deletions modules/markup/external/viewer3d.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package external

import (
"encoding/base64"
"fmt"
"html"
"io"
"path"

"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/public"
"code.gitea.io/gitea/modules/setting"
)

type viewer3dRenderer struct{}

var (
_ markup.PostProcessRenderer = (*viewer3dRenderer)(nil)
_ markup.ExternalRenderer = (*viewer3dRenderer)(nil)
)

func (p *viewer3dRenderer) Name() string {
return "viewer3d"
}

func (p *viewer3dRenderer) NeedPostProcess() bool {
return false
}

func (p *viewer3dRenderer) FileNamePatterns() []string {
return []string{
"*.3dm", "*.3ds", "*.3mf", "*.amf", "*.bim", "*.brep",
"*.dae", "*.fbx", "*.fcstd", "*.glb", "*.gltf",
"*.ifc", "*.igs", "*.iges", "*.stp", "*.step",
"*.stl", "*.obj", "*.off", "*.ply", "*.wrl",
}
}

func (p *viewer3dRenderer) SanitizerRules() []setting.MarkupSanitizerRule {
return nil
}

func (p *viewer3dRenderer) GetExternalRendererOptions() (ret markup.ExternalRendererOptions) {
ret.SanitizerDisabled = true
ret.DisplayInIframe = true
ret.ContentSandbox = "allow-scripts"
return ret
}

func (p *viewer3dRenderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
if ctx.RenderOptions.StandalonePageOptions == nil {
opts := p.GetExternalRendererOptions()
return markup.RenderIFrame(ctx, &opts, output)
}

if _, err := fmt.Fprintf(output,
`<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><style>html,body{margin:0;height:100%%}#viewer{width:100%%;height:100%%}#viewer>div{text-align:center;padding:1em}</style></head>
<body><div id="viewer"></div><script type="application/octet-stream" id="modelData" data-filename="%s">`,
html.EscapeString(path.Base(ctx.RenderOptions.RelativePath)),
); err != nil {
return err
}

b64 := base64.NewEncoder(base64.StdEncoding, output)
if _, err := io.Copy(b64, io.LimitReader(input, setting.UI.MaxDisplayFileSize)); err != nil {
return err
}
if err := b64.Close(); err != nil {
return err
}

_, err := fmt.Fprintf(output, `</script><script type="module" src="%s"></script></body></html>`, public.AssetURI("js/viewer-3d.js"))
return err
}
1 change: 1 addition & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export default defineConfig(commonViteOpts({
input: {
index: join(import.meta.dirname, 'web_src/js/index.ts'),
swagger: join(import.meta.dirname, 'web_src/js/swagger.ts'),
'viewer-3d': join(import.meta.dirname, 'web_src/js/viewer-3d.ts'),
Comment thread
wxiaoguang marked this conversation as resolved.
Outdated
'eventsource.sharedworker': join(import.meta.dirname, 'web_src/js/eventsource.sharedworker.ts'),
devtest: join(import.meta.dirname, 'web_src/css/devtest.css'),
...themes,
Expand Down
3 changes: 1 addition & 2 deletions web_src/js/features/file-view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {FileRenderPlugin} from '../render/plugin.ts';
import {newRenderPlugin3DViewer} from '../render/plugins/3d-viewer.ts';
import {newRenderPluginPdfViewer} from '../render/plugins/pdf-viewer.ts';
import {registerGlobalInitFunc} from '../modules/observer.ts';
import {createElementFromHTML, showElem, toggleElemClass} from '../utils/dom.ts';
Expand All @@ -10,7 +9,7 @@ const plugins: FileRenderPlugin[] = [];

function initPluginsOnce(): void {
if (plugins.length) return;
plugins.push(newRenderPlugin3DViewer(), newRenderPluginPdfViewer());
plugins.push(newRenderPluginPdfViewer());
}

function findFileRenderPlugin(filename: string, mimeType: string): FileRenderPlugin | null {
Expand Down
59 changes: 0 additions & 59 deletions web_src/js/render/plugins/3d-viewer.ts

This file was deleted.

13 changes: 13 additions & 0 deletions web_src/js/viewer-3d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import * as OV from 'online-3d-viewer';

const modelDataScript = document.querySelector<HTMLElement>('#modelData')!;
const fileName = modelDataScript.getAttribute('data-filename')!;
const fileBytes = Uint8Array.from(atob(modelDataScript.textContent), (c) => c.charCodeAt(0));

const container = document.querySelector<HTMLElement>('#viewer')!;
const viewer = new OV.EmbeddedViewer(container, {
backgroundColor: new OV.RGBAColor(59, 68, 76, 0),
defaultColor: new OV.RGBColor(65, 131, 196),
edgeSettings: new OV.EdgeSettings(false, new OV.RGBColor(0, 0, 0), 1),
Comment thread
wxiaoguang marked this conversation as resolved.
Outdated
});
viewer.LoadModelFromFileList([new File([fileBytes], fileName)]);