@stevejtrettel/shader-sandbox 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +391 -0
- package/bin/cli.js +389 -0
- package/dist-lib/app/App.d.ts +134 -0
- package/dist-lib/app/App.d.ts.map +1 -0
- package/dist-lib/app/App.js +570 -0
- package/dist-lib/app/types.d.ts +32 -0
- package/dist-lib/app/types.d.ts.map +1 -0
- package/dist-lib/app/types.js +6 -0
- package/dist-lib/editor/EditorPanel.d.ts +39 -0
- package/dist-lib/editor/EditorPanel.d.ts.map +1 -0
- package/dist-lib/editor/EditorPanel.js +274 -0
- package/dist-lib/editor/prism-editor.css +99 -0
- package/dist-lib/editor/prism-editor.d.ts +19 -0
- package/dist-lib/editor/prism-editor.d.ts.map +1 -0
- package/dist-lib/editor/prism-editor.js +96 -0
- package/dist-lib/embed.d.ts +17 -0
- package/dist-lib/embed.d.ts.map +1 -0
- package/dist-lib/embed.js +35 -0
- package/dist-lib/engine/ShadertoyEngine.d.ts +160 -0
- package/dist-lib/engine/ShadertoyEngine.d.ts.map +1 -0
- package/dist-lib/engine/ShadertoyEngine.js +704 -0
- package/dist-lib/engine/glHelpers.d.ts +79 -0
- package/dist-lib/engine/glHelpers.d.ts.map +1 -0
- package/dist-lib/engine/glHelpers.js +298 -0
- package/dist-lib/engine/types.d.ts +77 -0
- package/dist-lib/engine/types.d.ts.map +1 -0
- package/dist-lib/engine/types.js +7 -0
- package/dist-lib/index.d.ts +12 -0
- package/dist-lib/index.d.ts.map +1 -0
- package/dist-lib/index.js +9 -0
- package/dist-lib/layouts/DefaultLayout.d.ts +17 -0
- package/dist-lib/layouts/DefaultLayout.d.ts.map +1 -0
- package/dist-lib/layouts/DefaultLayout.js +27 -0
- package/dist-lib/layouts/FullscreenLayout.d.ts +17 -0
- package/dist-lib/layouts/FullscreenLayout.d.ts.map +1 -0
- package/dist-lib/layouts/FullscreenLayout.js +27 -0
- package/dist-lib/layouts/SplitLayout.d.ts +26 -0
- package/dist-lib/layouts/SplitLayout.d.ts.map +1 -0
- package/dist-lib/layouts/SplitLayout.js +61 -0
- package/dist-lib/layouts/TabbedLayout.d.ts +38 -0
- package/dist-lib/layouts/TabbedLayout.d.ts.map +1 -0
- package/dist-lib/layouts/TabbedLayout.js +305 -0
- package/dist-lib/layouts/index.d.ts +24 -0
- package/dist-lib/layouts/index.d.ts.map +1 -0
- package/dist-lib/layouts/index.js +36 -0
- package/dist-lib/layouts/split.css +196 -0
- package/dist-lib/layouts/tabbed.css +345 -0
- package/dist-lib/layouts/types.d.ts +48 -0
- package/dist-lib/layouts/types.d.ts.map +1 -0
- package/dist-lib/layouts/types.js +4 -0
- package/dist-lib/main.d.ts +15 -0
- package/dist-lib/main.d.ts.map +1 -0
- package/dist-lib/main.js +102 -0
- package/dist-lib/project/generatedLoader.d.ts +3 -0
- package/dist-lib/project/generatedLoader.d.ts.map +1 -0
- package/dist-lib/project/generatedLoader.js +17 -0
- package/dist-lib/project/loadProject.d.ts +22 -0
- package/dist-lib/project/loadProject.d.ts.map +1 -0
- package/dist-lib/project/loadProject.js +350 -0
- package/dist-lib/project/loaderHelper.d.ts +7 -0
- package/dist-lib/project/loaderHelper.d.ts.map +1 -0
- package/dist-lib/project/loaderHelper.js +240 -0
- package/dist-lib/project/types.d.ts +192 -0
- package/dist-lib/project/types.d.ts.map +1 -0
- package/dist-lib/project/types.js +7 -0
- package/dist-lib/styles/base.css +29 -0
- package/package.json +48 -0
- package/src/app/App.ts +699 -0
- package/src/app/app.css +208 -0
- package/src/app/types.ts +36 -0
- package/src/editor/EditorPanel.ts +340 -0
- package/src/editor/editor-panel.css +175 -0
- package/src/editor/prism-editor.css +99 -0
- package/src/editor/prism-editor.ts +124 -0
- package/src/embed.ts +55 -0
- package/src/engine/ShadertoyEngine.ts +929 -0
- package/src/engine/glHelpers.ts +432 -0
- package/src/engine/types.ts +118 -0
- package/src/index.ts +13 -0
- package/src/layouts/DefaultLayout.ts +40 -0
- package/src/layouts/FullscreenLayout.ts +40 -0
- package/src/layouts/SplitLayout.ts +81 -0
- package/src/layouts/TabbedLayout.ts +371 -0
- package/src/layouts/default.css +22 -0
- package/src/layouts/fullscreen.css +15 -0
- package/src/layouts/index.ts +44 -0
- package/src/layouts/split.css +196 -0
- package/src/layouts/tabbed.css +345 -0
- package/src/layouts/types.ts +58 -0
- package/src/main.ts +114 -0
- package/src/project/generatedLoader.ts +23 -0
- package/src/project/loadProject.ts +421 -0
- package/src/project/loaderHelper.ts +300 -0
- package/src/project/types.ts +243 -0
- package/src/styles/base.css +29 -0
- package/src/styles/embed.css +14 -0
- package/src/vite-env.d.ts +1 -0
- package/templates/index.html +28 -0
- package/templates/main.ts +126 -0
- package/templates/package.json +12 -0
- package/templates/shaders/example-buffer/bufferA.glsl +14 -0
- package/templates/shaders/example-buffer/config.json +10 -0
- package/templates/shaders/example-buffer/image.glsl +5 -0
- package/templates/shaders/example-gradient/config.json +4 -0
- package/templates/shaders/example-gradient/image.glsl +7 -0
- package/templates/vite.config.js +35 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor Panel Styles
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/* Toolbar with tabs and recompile button */
|
|
6
|
+
.editor-toolbar {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
background: #f8f8f8;
|
|
10
|
+
border-bottom: 1px solid #e0e0e0;
|
|
11
|
+
padding-right: 8px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.editor-tab-bar {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex: 1;
|
|
17
|
+
overflow-x: auto;
|
|
18
|
+
scrollbar-width: thin;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.editor-tab-button {
|
|
22
|
+
background: transparent;
|
|
23
|
+
border: none;
|
|
24
|
+
color: #666;
|
|
25
|
+
padding: 10px 16px;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
28
|
+
font-size: 12px;
|
|
29
|
+
white-space: nowrap;
|
|
30
|
+
border-bottom: 2px solid transparent;
|
|
31
|
+
transition: color 0.15s, border-color 0.15s;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.editor-tab-button:hover {
|
|
35
|
+
color: #333;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.editor-tab-button.active {
|
|
39
|
+
color: #000;
|
|
40
|
+
border-bottom-color: #4a9eff;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.editor-tab-button.image-tab {
|
|
44
|
+
color: #7c4dff;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.editor-tab-button.image-tab.active {
|
|
48
|
+
color: #7c4dff;
|
|
49
|
+
border-bottom-color: #7c4dff;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Copy button (icon only) */
|
|
53
|
+
.editor-copy-button {
|
|
54
|
+
display: flex;
|
|
55
|
+
align-items: center;
|
|
56
|
+
justify-content: center;
|
|
57
|
+
background: transparent;
|
|
58
|
+
border: 1px solid #ccc;
|
|
59
|
+
color: #666;
|
|
60
|
+
width: 32px;
|
|
61
|
+
height: 32px;
|
|
62
|
+
border-radius: 4px;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
transition: background 0.15s, border-color 0.15s, color 0.15s;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
margin-right: 6px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.editor-copy-button:hover {
|
|
70
|
+
background: #f0f0f0;
|
|
71
|
+
border-color: #999;
|
|
72
|
+
color: #333;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.editor-copy-button:active {
|
|
76
|
+
background: #e0e0e0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.editor-copy-button.copied {
|
|
80
|
+
background: #e8f5e9;
|
|
81
|
+
border-color: #4caf50;
|
|
82
|
+
color: #4caf50;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.editor-copy-button svg {
|
|
86
|
+
flex-shrink: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Recompile button */
|
|
90
|
+
.editor-recompile-button {
|
|
91
|
+
display: flex;
|
|
92
|
+
align-items: center;
|
|
93
|
+
gap: 6px;
|
|
94
|
+
background: #4a9eff;
|
|
95
|
+
border: none;
|
|
96
|
+
color: #fff;
|
|
97
|
+
padding: 6px 12px;
|
|
98
|
+
border-radius: 4px;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
font-family: inherit;
|
|
101
|
+
font-size: 12px;
|
|
102
|
+
font-weight: 500;
|
|
103
|
+
transition: background 0.15s;
|
|
104
|
+
flex-shrink: 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.editor-recompile-button:hover {
|
|
108
|
+
background: #3a8eef;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.editor-recompile-button:active {
|
|
112
|
+
background: #2a7edf;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.editor-recompile-button svg {
|
|
116
|
+
flex-shrink: 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Content area */
|
|
120
|
+
.editor-content-area {
|
|
121
|
+
flex: 1;
|
|
122
|
+
overflow: hidden;
|
|
123
|
+
position: relative;
|
|
124
|
+
background: #ffffff;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.editor-prism-container {
|
|
128
|
+
height: 100%;
|
|
129
|
+
width: 100%;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Fallback textarea */
|
|
133
|
+
.editor-fallback-textarea {
|
|
134
|
+
width: 100%;
|
|
135
|
+
height: 100%;
|
|
136
|
+
background: #ffffff;
|
|
137
|
+
color: #000;
|
|
138
|
+
border: none;
|
|
139
|
+
padding: 12px;
|
|
140
|
+
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
141
|
+
font-size: 13px;
|
|
142
|
+
resize: none;
|
|
143
|
+
outline: none;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Image viewer */
|
|
147
|
+
.editor-image-viewer {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
justify-content: center;
|
|
151
|
+
height: 100%;
|
|
152
|
+
background: #f5f5f5;
|
|
153
|
+
padding: 20px;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.editor-image-viewer img {
|
|
157
|
+
max-width: 100%;
|
|
158
|
+
max-height: 100%;
|
|
159
|
+
object-fit: contain;
|
|
160
|
+
border-radius: 4px;
|
|
161
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/* Error display */
|
|
165
|
+
.editor-error-display {
|
|
166
|
+
background: #fff0f0;
|
|
167
|
+
color: #c00;
|
|
168
|
+
padding: 10px 14px;
|
|
169
|
+
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
170
|
+
font-size: 12px;
|
|
171
|
+
white-space: pre-wrap;
|
|
172
|
+
overflow: auto;
|
|
173
|
+
max-height: 120px;
|
|
174
|
+
border-top: 1px solid #fcc;
|
|
175
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prism Editor Styles
|
|
3
|
+
* Textarea + syntax highlighting overlay
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
.prism-editor-wrapper {
|
|
7
|
+
display: flex;
|
|
8
|
+
height: 100%;
|
|
9
|
+
background: #ffffff;
|
|
10
|
+
font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
|
|
11
|
+
font-size: 13px;
|
|
12
|
+
line-height: 1.6;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Line numbers column */
|
|
16
|
+
.prism-editor-line-numbers {
|
|
17
|
+
flex-shrink: 0;
|
|
18
|
+
padding: 16px 12px 16px 16px;
|
|
19
|
+
text-align: right;
|
|
20
|
+
color: #999;
|
|
21
|
+
border-right: 1px solid #e0e0e0;
|
|
22
|
+
user-select: none;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.prism-editor-line-numbers span {
|
|
27
|
+
display: block;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Editor area containing textarea and highlight overlay */
|
|
31
|
+
.prism-editor-area {
|
|
32
|
+
flex: 1;
|
|
33
|
+
position: relative;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Shared styles for textarea and highlight */
|
|
38
|
+
.prism-editor-textarea,
|
|
39
|
+
.prism-editor-highlight {
|
|
40
|
+
position: absolute;
|
|
41
|
+
top: 0;
|
|
42
|
+
left: 0;
|
|
43
|
+
width: 100%;
|
|
44
|
+
height: 100%;
|
|
45
|
+
padding: 16px;
|
|
46
|
+
margin: 0;
|
|
47
|
+
border: none;
|
|
48
|
+
outline: none;
|
|
49
|
+
font-family: inherit;
|
|
50
|
+
font-size: inherit;
|
|
51
|
+
line-height: inherit;
|
|
52
|
+
white-space: pre-wrap;
|
|
53
|
+
word-wrap: break-word;
|
|
54
|
+
overflow: auto;
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* Textarea - user types here */
|
|
59
|
+
.prism-editor-textarea {
|
|
60
|
+
background: transparent;
|
|
61
|
+
color: transparent;
|
|
62
|
+
caret-color: #000;
|
|
63
|
+
resize: none;
|
|
64
|
+
z-index: 1;
|
|
65
|
+
-webkit-text-fill-color: transparent;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.prism-editor-textarea::selection {
|
|
69
|
+
background: rgba(173, 214, 255, 0.4);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.prism-editor-textarea::-moz-selection {
|
|
73
|
+
background: rgba(173, 214, 255, 0.4);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Highlighted code overlay */
|
|
77
|
+
.prism-editor-highlight {
|
|
78
|
+
background: #ffffff;
|
|
79
|
+
color: #000;
|
|
80
|
+
pointer-events: none;
|
|
81
|
+
z-index: 0;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.prism-editor-highlight code {
|
|
85
|
+
font-family: inherit;
|
|
86
|
+
font-size: inherit;
|
|
87
|
+
background: none;
|
|
88
|
+
padding: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Prism syntax highlighting colors */
|
|
92
|
+
.prism-editor-highlight .token.comment { color: #6a9955; }
|
|
93
|
+
.prism-editor-highlight .token.keyword { color: #0000ff; }
|
|
94
|
+
.prism-editor-highlight .token.string { color: #a31515; }
|
|
95
|
+
.prism-editor-highlight .token.number { color: #098658; }
|
|
96
|
+
.prism-editor-highlight .token.operator { color: #000000; }
|
|
97
|
+
.prism-editor-highlight .token.function { color: #795e26; }
|
|
98
|
+
.prism-editor-highlight .token.class-name { color: #267f99; }
|
|
99
|
+
.prism-editor-highlight .token.punctuation { color: #000000; }
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight Prism Editor
|
|
3
|
+
*
|
|
4
|
+
* Simple textarea with Prism syntax highlighting overlay.
|
|
5
|
+
* Uses the existing Prism.js dependency - adds ~0 extra bytes to bundle.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as Prism from 'prismjs';
|
|
9
|
+
import 'prismjs/components/prism-c';
|
|
10
|
+
import 'prismjs/components/prism-cpp';
|
|
11
|
+
|
|
12
|
+
import './prism-editor.css';
|
|
13
|
+
|
|
14
|
+
export interface EditorInstance {
|
|
15
|
+
getSource: () => string;
|
|
16
|
+
setSource: (source: string) => void;
|
|
17
|
+
destroy: () => void;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a lightweight editor with Prism syntax highlighting.
|
|
22
|
+
*/
|
|
23
|
+
export function createEditor(
|
|
24
|
+
container: HTMLElement,
|
|
25
|
+
initialSource: string,
|
|
26
|
+
onChange?: (source: string) => void
|
|
27
|
+
): EditorInstance {
|
|
28
|
+
// Create wrapper
|
|
29
|
+
const wrapper = document.createElement('div');
|
|
30
|
+
wrapper.className = 'prism-editor-wrapper';
|
|
31
|
+
|
|
32
|
+
// Create line numbers
|
|
33
|
+
const lineNumbers = document.createElement('div');
|
|
34
|
+
lineNumbers.className = 'prism-editor-line-numbers';
|
|
35
|
+
|
|
36
|
+
// Create editor area (textarea + highlighted overlay)
|
|
37
|
+
const editorArea = document.createElement('div');
|
|
38
|
+
editorArea.className = 'prism-editor-area';
|
|
39
|
+
|
|
40
|
+
// Create textarea (user types here)
|
|
41
|
+
const textarea = document.createElement('textarea');
|
|
42
|
+
textarea.className = 'prism-editor-textarea';
|
|
43
|
+
textarea.value = initialSource;
|
|
44
|
+
textarea.spellcheck = false;
|
|
45
|
+
textarea.autocapitalize = 'off';
|
|
46
|
+
textarea.autocomplete = 'off';
|
|
47
|
+
|
|
48
|
+
// Create highlighted code overlay
|
|
49
|
+
const highlight = document.createElement('pre');
|
|
50
|
+
highlight.className = 'prism-editor-highlight';
|
|
51
|
+
const code = document.createElement('code');
|
|
52
|
+
code.className = 'language-cpp';
|
|
53
|
+
highlight.appendChild(code);
|
|
54
|
+
|
|
55
|
+
// Assemble
|
|
56
|
+
editorArea.appendChild(textarea);
|
|
57
|
+
editorArea.appendChild(highlight);
|
|
58
|
+
wrapper.appendChild(lineNumbers);
|
|
59
|
+
wrapper.appendChild(editorArea);
|
|
60
|
+
container.appendChild(wrapper);
|
|
61
|
+
|
|
62
|
+
// Update highlighting and line numbers
|
|
63
|
+
function update() {
|
|
64
|
+
const source = textarea.value;
|
|
65
|
+
|
|
66
|
+
// Update highlighted code
|
|
67
|
+
// Add a trailing newline to prevent layout shift when typing at end
|
|
68
|
+
code.textContent = source + '\n';
|
|
69
|
+
Prism.highlightElement(code);
|
|
70
|
+
|
|
71
|
+
// Update line numbers
|
|
72
|
+
const lines = source.split('\n');
|
|
73
|
+
lineNumbers.innerHTML = lines.map((_, i) => `<span>${i + 1}</span>`).join('');
|
|
74
|
+
|
|
75
|
+
// Notify listener
|
|
76
|
+
if (onChange) {
|
|
77
|
+
onChange(source);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Sync scroll position
|
|
82
|
+
function syncScroll() {
|
|
83
|
+
highlight.scrollTop = textarea.scrollTop;
|
|
84
|
+
highlight.scrollLeft = textarea.scrollLeft;
|
|
85
|
+
lineNumbers.scrollTop = textarea.scrollTop;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Handle tab key for indentation
|
|
89
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
90
|
+
if (e.key === 'Tab') {
|
|
91
|
+
e.preventDefault();
|
|
92
|
+
const start = textarea.selectionStart;
|
|
93
|
+
const end = textarea.selectionEnd;
|
|
94
|
+
const value = textarea.value;
|
|
95
|
+
|
|
96
|
+
// Insert 2 spaces
|
|
97
|
+
textarea.value = value.substring(0, start) + ' ' + value.substring(end);
|
|
98
|
+
textarea.selectionStart = textarea.selectionEnd = start + 2;
|
|
99
|
+
update();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Set up event listeners
|
|
104
|
+
textarea.addEventListener('input', update);
|
|
105
|
+
textarea.addEventListener('scroll', syncScroll);
|
|
106
|
+
textarea.addEventListener('keydown', handleKeydown);
|
|
107
|
+
|
|
108
|
+
// Initial render
|
|
109
|
+
update();
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
getSource: () => textarea.value,
|
|
113
|
+
setSource: (source: string) => {
|
|
114
|
+
textarea.value = source;
|
|
115
|
+
update();
|
|
116
|
+
},
|
|
117
|
+
destroy: () => {
|
|
118
|
+
textarea.removeEventListener('input', update);
|
|
119
|
+
textarea.removeEventListener('scroll', syncScroll);
|
|
120
|
+
textarea.removeEventListener('keydown', handleKeydown);
|
|
121
|
+
container.removeChild(wrapper);
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
package/src/embed.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embeddable Entry Point
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import './styles/embed.css'; // <-- changed from base.css
|
|
6
|
+
|
|
7
|
+
import { App } from './app/App';
|
|
8
|
+
import { createLayout } from './layouts';
|
|
9
|
+
import { loadDemoProject, DEMO_NAME } from './project/generatedLoader';
|
|
10
|
+
|
|
11
|
+
export interface EmbedOptions {
|
|
12
|
+
container: HTMLElement | string;
|
|
13
|
+
pixelRatio?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface EmbedResult {
|
|
17
|
+
app: App;
|
|
18
|
+
destroy: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function embed(options: EmbedOptions): Promise<EmbedResult> {
|
|
22
|
+
const container = typeof options.container === 'string'
|
|
23
|
+
? document.querySelector(options.container)
|
|
24
|
+
: options.container;
|
|
25
|
+
|
|
26
|
+
if (!container || !(container instanceof HTMLElement)) {
|
|
27
|
+
throw new Error(`Container not found: ${options.container}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const project = await loadDemoProject();
|
|
31
|
+
|
|
32
|
+
const layout = createLayout(project.layout, {
|
|
33
|
+
container,
|
|
34
|
+
project,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const app = new App({
|
|
38
|
+
container: layout.getCanvasContainer(),
|
|
39
|
+
project,
|
|
40
|
+
pixelRatio: options.pixelRatio ?? window.devicePixelRatio,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (!app.hasErrors()) {
|
|
44
|
+
app.start();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
app,
|
|
49
|
+
destroy: () => {
|
|
50
|
+
app.stop?.();
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export { DEMO_NAME };
|