├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── package.json
├── public
├── _redirects
├── favicon.ico
├── img
│ ├── featured_projects
│ │ ├── LAS Site.jpg
│ │ ├── Quantum Summer Site.jpg
│ │ └── WCMA Site.jpg
│ └── icons
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-256x256.png
│ │ ├── apple-touch-icon.png
│ │ ├── browserconfig.xml
│ │ ├── discord.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon.ico
│ │ ├── favicon.png
│ │ ├── github.png
│ │ ├── glitch.png
│ │ ├── hicetnunc.png
│ │ ├── msdf-left-align.png
│ │ ├── mstile-150x150.png
│ │ ├── p5.png
│ │ ├── safari-pinned-tab.svg
│ │ ├── sp-hero.png
│ │ ├── sp_logo.png
│ │ ├── sphere.jpg
│ │ ├── threejs.png
│ │ ├── touchdesigner.png
│ │ └── webclip.png
├── index.html
└── robots.txt
├── src
├── App.vue
├── client
│ ├── codemirror
│ │ ├── codemirror.css
│ │ ├── glslEditor.css
│ │ └── glslEditor.js
│ ├── fonts
│ │ ├── RegolaPro-Bold.woff2
│ │ └── RegolaPro-Book.woff2
│ ├── images
│ │ ├── Heart.svg
│ │ ├── Heart_filled.svg
│ │ ├── close-white.svg
│ │ ├── close.svg
│ │ ├── favicon.png
│ │ ├── glitch_logo.svg
│ │ ├── msdf-left-align.png
│ │ ├── msdf3.png
│ │ ├── play.svg
│ │ ├── share.svg
│ │ ├── sp_logo.png
│ │ ├── touchdesigner_logo.jpg
│ │ └── webclip.png
│ ├── mixins.less
│ ├── normalize.css
│ ├── style.css
│ └── webflow.css
├── components
│ ├── About.vue
│ ├── ActionBar.vue
│ ├── CardModal.vue
│ ├── Editor.vue
│ ├── Error404.vue
│ ├── Examples.vue
│ ├── Explore.vue
│ ├── Header.vue
│ ├── Home.vue
│ ├── Home3D.vue
│ ├── MainContainer.vue
│ ├── New.vue
│ ├── Profile.vue
│ ├── Room.vue
│ ├── Sculpture.vue
│ ├── SculptureFeed.vue
│ ├── ShareModal.vue
│ ├── SignIn.vue
│ ├── SignUp.vue
│ ├── SpThreeVue.vue
│ └── UniformGUI.vue
├── dbConfig.js
├── helpers
│ ├── front-page-sculp1.js
│ └── handelUnsavedChanges.js
├── main.js
├── registerServiceWorker.js
├── router
│ └── routes.js
├── schema
│ └── User.js
├── store
│ └── store.js
├── sublime.js
└── threejs-sculpture
│ ├── SculptureN.js
│ └── create-pedestal-edges.js
├── vue.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 shader-park
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Shader Park
2 |
3 | [](https://app.netlify.com/sites/shaderpark/deploys)
4 |
5 | ## Project setup
6 | ```
7 | yarn install
8 | ```
9 |
10 | ### Compiles and hot-reloads for development
11 | ```
12 | yarn serve
13 | ```
14 |
15 | ### Compiles and minifies for production
16 | ```
17 | yarn build
18 | ```
19 |
20 | ### Customize configuration
21 | See [Configuration Reference](https://cli.vuejs.org/config/).
22 |
23 | ## Project Deploy
24 | ```
25 | git checkout staging
26 | git merge master
27 | git push
28 | ```
29 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Shader-Park-Website",
3 | "version": "0.1.0",
4 | "private": true,
5 | "author": "Peter Whidden, Torin Blankensmith",
6 | "scripts": {
7 | "serve": "vue-cli-service serve",
8 | "build": "vue-cli-service build"
9 | },
10 | "dependencies": {
11 | "@tweenjs/tween.js": "^18.5.0",
12 | "animejs": "^3.1.0",
13 | "core-js": "^3.6.4",
14 | "dat.gui": "^0.7.6",
15 | "firebase": "^9.6.8",
16 | "intersection-observer": "^0.7.0",
17 | "lodash.throttle": "^4.1.1",
18 | "register-service-worker": "^1.6.2",
19 | "shader-park-core": "^0.2.5",
20 | "three": "^0.155.0",
21 | "v-lazy-image": "^1.3.2",
22 | "vue": "^2.6.11",
23 | "vue-codemirror": "^4.0.6",
24 | "vue-github-button": "^1.2.0",
25 | "vue-js-modal": "^1.3.33",
26 | "vue-meta": "^2.3.2",
27 | "vue-router": "^3.1.5",
28 | "vuelidate": "^0.7.5",
29 | "vuex": "^3.1.2"
30 | },
31 | "devDependencies": {
32 | "@babel/core": "^7.17.5",
33 | "@babel/preset-env": "^7.16.11",
34 | "@vue/cli-plugin-babel": "~5.0.1",
35 | "@vue/cli-plugin-pwa": "~5.0.1",
36 | "@vue/cli-plugin-router": "~5.0.1",
37 | "@vue/cli-plugin-vuex": "~5.0.1",
38 | "@vue/cli-service": "~5.0.1",
39 | "less": "^4.1.2",
40 | "less-loader": "^10.2.0",
41 | "vue-template-compiler": "^2.6.11"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/public/_redirects:
--------------------------------------------------------------------------------
1 | # Netlify settings for single-page application
2 | /* /index.html 200
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/featured_projects/LAS Site.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/featured_projects/LAS Site.jpg
--------------------------------------------------------------------------------
/public/img/featured_projects/Quantum Summer Site.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/featured_projects/Quantum Summer Site.jpg
--------------------------------------------------------------------------------
/public/img/featured_projects/WCMA Site.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/featured_projects/WCMA Site.jpg
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/android-chrome-256x256.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/img/icons/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #2b5797
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/public/img/icons/discord.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/discord.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/img/icons/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/favicon.ico
--------------------------------------------------------------------------------
/public/img/icons/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/favicon.png
--------------------------------------------------------------------------------
/public/img/icons/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/github.png
--------------------------------------------------------------------------------
/public/img/icons/glitch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/glitch.png
--------------------------------------------------------------------------------
/public/img/icons/hicetnunc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/hicetnunc.png
--------------------------------------------------------------------------------
/public/img/icons/msdf-left-align.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/msdf-left-align.png
--------------------------------------------------------------------------------
/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/public/img/icons/p5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/p5.png
--------------------------------------------------------------------------------
/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/public/img/icons/sp-hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/sp-hero.png
--------------------------------------------------------------------------------
/public/img/icons/sp_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/sp_logo.png
--------------------------------------------------------------------------------
/public/img/icons/sphere.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/sphere.jpg
--------------------------------------------------------------------------------
/public/img/icons/threejs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/threejs.png
--------------------------------------------------------------------------------
/public/img/icons/touchdesigner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/touchdesigner.png
--------------------------------------------------------------------------------
/public/img/icons/webclip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/public/img/icons/webclip.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Shader Park
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
35 |
36 |
37 | Shader Park
38 |
39 |
40 |
41 | We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shader Park
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
133 |
134 |
178 |
179 |
352 |
353 |
354 |
--------------------------------------------------------------------------------
/src/client/codemirror/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | direction: ltr;
9 | }
10 |
11 | /* PADDING */
12 |
13 | .CodeMirror-lines {
14 | padding: 4px 0; /* Vertical padding around content */
15 | }
16 | .CodeMirror pre.CodeMirror-line,
17 | .CodeMirror pre.CodeMirror-line-like {
18 | padding: 0 4px; /* Horizontal padding of content */
19 | }
20 |
21 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
22 | background-color: white; /* The little square between H and V scrollbars */
23 | }
24 |
25 | /* GUTTER */
26 |
27 | .CodeMirror-gutters {
28 | border-right: 1px solid #ddd;
29 | background-color: #f7f7f7;
30 | white-space: nowrap;
31 | }
32 | .CodeMirror-linenumbers {}
33 | .CodeMirror-linenumber {
34 | padding: 0 3px 0 5px;
35 | min-width: 20px;
36 | text-align: right;
37 | color: #999;
38 | white-space: nowrap;
39 | }
40 |
41 | .CodeMirror-guttermarker { color: black; }
42 | .CodeMirror-guttermarker-subtle { color: #999; }
43 |
44 | /* CURSOR */
45 |
46 | .CodeMirror-cursor {
47 | border-left: 1px solid black;
48 | border-right: none;
49 | width: 0;
50 | }
51 | /* Shown when moving in bi-directional text */
52 | .CodeMirror div.CodeMirror-secondarycursor {
53 | border-left: 1px solid silver;
54 | }
55 | .cm-fat-cursor .CodeMirror-cursor {
56 | width: auto;
57 | border: 0 !important;
58 | background: #7e7;
59 | }
60 | .cm-fat-cursor div.CodeMirror-cursors {
61 | z-index: 1;
62 | }
63 | .cm-fat-cursor-mark {
64 | background-color: rgba(20, 255, 20, 0.5);
65 | -webkit-animation: blink 1.06s steps(1) infinite;
66 | -moz-animation: blink 1.06s steps(1) infinite;
67 | animation: blink 1.06s steps(1) infinite;
68 | }
69 | .cm-animate-fat-cursor {
70 | width: auto;
71 | border: 0;
72 | -webkit-animation: blink 1.06s steps(1) infinite;
73 | -moz-animation: blink 1.06s steps(1) infinite;
74 | animation: blink 1.06s steps(1) infinite;
75 | background-color: #7e7;
76 | }
77 | @-moz-keyframes blink {
78 | 0% {}
79 | 50% { background-color: transparent; }
80 | 100% {}
81 | }
82 | @-webkit-keyframes blink {
83 | 0% {}
84 | 50% { background-color: transparent; }
85 | 100% {}
86 | }
87 | @keyframes blink {
88 | 0% {}
89 | 50% { background-color: transparent; }
90 | 100% {}
91 | }
92 |
93 | /* Can style cursor different in overwrite (non-insert) mode */
94 | .CodeMirror-overwrite .CodeMirror-cursor {}
95 |
96 | .cm-tab { display: inline-block; text-decoration: inherit; }
97 |
98 | .CodeMirror-rulers {
99 | position: absolute;
100 | left: 0; right: 0; top: -50px; bottom: 0;
101 | overflow: hidden;
102 | }
103 | .CodeMirror-ruler {
104 | border-left: 1px solid #ccc;
105 | top: 0; bottom: 0;
106 | position: absolute;
107 | }
108 |
109 | /* DEFAULT THEME */
110 |
111 | .cm-s-default .cm-header {color: blue;}
112 | .cm-s-default .cm-quote {color: #090;}
113 | .cm-negative {color: #d44;}
114 | .cm-positive {color: #292;}
115 | .cm-header, .cm-strong {font-weight: bold;}
116 | .cm-em {font-style: italic;}
117 | .cm-link {text-decoration: underline;}
118 | .cm-strikethrough {text-decoration: line-through;}
119 |
120 | .cm-s-default .cm-keyword {color: #708;}
121 | .cm-s-default .cm-atom {color: #219;}
122 | .cm-s-default .cm-number {color: #164;}
123 | .cm-s-default .cm-def {color: #00f;}
124 | .cm-s-default .cm-variable,
125 | .cm-s-default .cm-punctuation,
126 | .cm-s-default .cm-property,
127 | .cm-s-default .cm-operator {}
128 | .cm-s-default .cm-variable-2 {color: #05a;}
129 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;}
130 | .cm-s-default .cm-comment {color: #a50;}
131 | .cm-s-default .cm-string {color: #a11;}
132 | .cm-s-default .cm-string-2 {color: #f50;}
133 | .cm-s-default .cm-meta {color: #555;}
134 | .cm-s-default .cm-qualifier {color: #555;}
135 | .cm-s-default .cm-builtin {color: #30a;}
136 | .cm-s-default .cm-bracket {color: #997;}
137 | .cm-s-default .cm-tag {color: #170;}
138 | .cm-s-default .cm-attribute {color: #00c;}
139 | .cm-s-default .cm-hr {color: #999;}
140 | .cm-s-default .cm-link {color: #00c;}
141 |
142 | .cm-s-default .cm-error {color: #f00;}
143 | .cm-invalidchar {color: #f00;}
144 |
145 | .CodeMirror-composing { border-bottom: 2px solid; }
146 |
147 | /* Default styles for common addons */
148 |
149 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;}
150 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;}
151 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
152 | .CodeMirror-activeline-background {background: #e8f2ff;}
153 |
154 | /* STOP */
155 |
156 | /* The rest of this file contains styles related to the mechanics of
157 | the editor. You probably shouldn't touch them. */
158 |
159 | .CodeMirror {
160 | position: relative;
161 | overflow: hidden;
162 | background: white;
163 | }
164 |
165 | .CodeMirror-scroll {
166 | overflow: scroll !important; /* Things will break if this is overridden */
167 | /* 30px is the magic margin used to hide the element's real scrollbars */
168 | /* See overflow: hidden in .CodeMirror */
169 | margin-bottom: -30px; margin-right: -30px;
170 | padding-bottom: 30px;
171 | height: 100%;
172 | outline: none; /* Prevent dragging from highlighting the element */
173 | position: relative;
174 | }
175 | .CodeMirror-sizer {
176 | position: relative;
177 | border-right: 30px solid transparent;
178 | }
179 |
180 | /* The fake, visible scrollbars. Used to force redraw during scrolling
181 | before actual scrolling happens, thus preventing shaking and
182 | flickering artifacts. */
183 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
184 | position: absolute;
185 | z-index: 6;
186 | display: none;
187 | }
188 | .CodeMirror-vscrollbar {
189 | right: 0; top: 0;
190 | overflow-x: hidden;
191 | overflow-y: scroll;
192 | }
193 | .CodeMirror-hscrollbar {
194 | bottom: 0; left: 0;
195 | overflow-y: hidden;
196 | overflow-x: scroll;
197 | }
198 | .CodeMirror-scrollbar-filler {
199 | right: 0; bottom: 0;
200 | }
201 | .CodeMirror-gutter-filler {
202 | left: 0; bottom: 0;
203 | }
204 |
205 | .CodeMirror-gutters {
206 | position: absolute; left: 0; top: 0;
207 | min-height: 100%;
208 | z-index: 3;
209 | }
210 | .CodeMirror-gutter {
211 | white-space: normal;
212 | height: 100%;
213 | display: inline-block;
214 | vertical-align: top;
215 | margin-bottom: -30px;
216 | }
217 | .CodeMirror-gutter-wrapper {
218 | position: absolute;
219 | z-index: 4;
220 | background: none !important;
221 | border: none !important;
222 | }
223 | .CodeMirror-gutter-background {
224 | position: absolute;
225 | top: 0; bottom: 0;
226 | z-index: 4;
227 | }
228 | .CodeMirror-gutter-elt {
229 | position: absolute;
230 | cursor: default;
231 | z-index: 4;
232 | }
233 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent }
234 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent }
235 |
236 | .CodeMirror-lines {
237 | cursor: text;
238 | min-height: 1px; /* prevents collapsing before first draw */
239 | }
240 | .CodeMirror pre.CodeMirror-line,
241 | .CodeMirror pre.CodeMirror-line-like {
242 | /* Reset some styles that the rest of the page might have set */
243 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
244 | border-width: 0;
245 | background: transparent;
246 | font-family: inherit;
247 | font-size: inherit;
248 | margin: 0;
249 | white-space: pre;
250 | word-wrap: normal;
251 | line-height: inherit;
252 | color: inherit;
253 | z-index: 2;
254 | position: relative;
255 | overflow: visible;
256 | -webkit-tap-highlight-color: transparent;
257 | -webkit-font-variant-ligatures: contextual;
258 | font-variant-ligatures: contextual;
259 | }
260 | .CodeMirror-wrap pre.CodeMirror-line,
261 | .CodeMirror-wrap pre.CodeMirror-line-like {
262 | word-wrap: break-word;
263 | white-space: pre-wrap;
264 | word-break: normal;
265 | }
266 |
267 | .CodeMirror-linebackground {
268 | position: absolute;
269 | left: 0; right: 0; top: 0; bottom: 0;
270 | z-index: 0;
271 | }
272 |
273 | .CodeMirror-linewidget {
274 | position: relative;
275 | z-index: 2;
276 | padding: 0.1px; /* Force widget margins to stay inside of the container */
277 | }
278 |
279 | .CodeMirror-widget {}
280 |
281 | .CodeMirror-rtl pre { direction: rtl; }
282 |
283 | .CodeMirror-code {
284 | outline: none;
285 | }
286 |
287 | /* Force content-box sizing for the elements where we expect it */
288 | .CodeMirror-scroll,
289 | .CodeMirror-sizer,
290 | .CodeMirror-gutter,
291 | .CodeMirror-gutters,
292 | .CodeMirror-linenumber {
293 | -moz-box-sizing: content-box;
294 | box-sizing: content-box;
295 | }
296 |
297 | .CodeMirror-measure {
298 | position: absolute;
299 | width: 100%;
300 | height: 0;
301 | overflow: hidden;
302 | visibility: hidden;
303 | }
304 |
305 | .CodeMirror-cursor {
306 | position: absolute;
307 | pointer-events: none;
308 | }
309 | .CodeMirror-measure pre { position: static; }
310 |
311 | div.CodeMirror-cursors {
312 | visibility: hidden;
313 | position: relative;
314 | z-index: 3;
315 | }
316 | div.CodeMirror-dragcursors {
317 | visibility: visible;
318 | }
319 |
320 | .CodeMirror-focused div.CodeMirror-cursors {
321 | visibility: visible;
322 | }
323 |
324 | .CodeMirror-selected { background: #d9d9d9; }
325 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
326 | .CodeMirror-crosshair { cursor: crosshair; }
327 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
328 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
329 |
330 | .cm-searching {
331 | background-color: #ffa;
332 | background-color: rgba(255, 255, 0, .4);
333 | }
334 |
335 | /* Used to force a border model for a node */
336 | .cm-force-border { padding-right: .1px; }
337 |
338 | @media print {
339 | /* Hide the cursor when printing */
340 | .CodeMirror div.CodeMirror-cursors {
341 | visibility: hidden;
342 | }
343 | }
344 |
345 | /* See issue #2901 */
346 | .cm-tab-wrap-hack:after { content: ''; }
347 |
348 | /* Help users use markselection to safely style text background */
349 | span.CodeMirror-selectedtext { background: none; }
350 |
--------------------------------------------------------------------------------
/src/client/fonts/RegolaPro-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/fonts/RegolaPro-Bold.woff2
--------------------------------------------------------------------------------
/src/client/fonts/RegolaPro-Book.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/fonts/RegolaPro-Book.woff2
--------------------------------------------------------------------------------
/src/client/images/Heart.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/client/images/Heart_filled.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/client/images/close-white.svg:
--------------------------------------------------------------------------------
1 | close-white
--------------------------------------------------------------------------------
/src/client/images/close.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/client/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/images/favicon.png
--------------------------------------------------------------------------------
/src/client/images/glitch_logo.svg:
--------------------------------------------------------------------------------
1 | logo-day
--------------------------------------------------------------------------------
/src/client/images/msdf-left-align.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/images/msdf-left-align.png
--------------------------------------------------------------------------------
/src/client/images/msdf3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/images/msdf3.png
--------------------------------------------------------------------------------
/src/client/images/play.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Shape
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/client/images/share.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/client/images/sp_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/images/sp_logo.png
--------------------------------------------------------------------------------
/src/client/images/touchdesigner_logo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/images/touchdesigner_logo.jpg
--------------------------------------------------------------------------------
/src/client/images/webclip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shader-park/shader-park-website/e80177941cc96605aa86c7ca3de145354514c752/src/client/images/webclip.png
--------------------------------------------------------------------------------
/src/client/mixins.less:
--------------------------------------------------------------------------------
1 | .smallDesktop(@rules) {
2 | @media (max-width: 1100px) {
3 | @rules();
4 | }
5 | }
6 |
7 | .mobile(@rules) {
8 | @media (max-width: 580px) {
9 | @rules();
10 | }
11 | }
12 |
13 | .editor-button {
14 | .mobile({
15 | font-size: 14 !important;
16 | padding: 3px 13px 3px 13px;
17 | });
18 | padding: 5px 15px 5px 15px;
19 | border-radius: 50px;
20 | /* border: 1px solid lightgrey; */
21 | box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.15);
22 | margin-bottom: 5px;
23 | transition: color 300ms ease-in-out, box-shadow 300ms ease-in-out ;
24 | color: #777;
25 | -webkit-transition: color 300ms ease-in-out, box-shadow 300ms ease-in-out ;
26 | background-repeat: no-repeat, no-repeat;
27 | &:hover {
28 | color: #000;
29 | box-shadow: 0 1px 4px 0 rgba(0, 0, 0, 0.2);
30 | }
31 | }
32 |
33 |
34 | .control-button {
35 | .mobile({
36 | font-size: 14 !important;
37 | padding: 3px 13px 3px 13px;
38 | });
39 | opacity: 0.55;
40 | background-repeat: no-repeat;
41 | // box-shadow: none;
42 | transition: opacity 300ms ease-in-out;
43 | -webkit-transition: opacity 300ms ease-in-out;
44 | &:hover {
45 | // box-shadow: none;
46 | opacity: 1.0;
47 | }
48 | }
--------------------------------------------------------------------------------
/src/client/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
2 | /**
3 | * 1. Set default font family to sans-serif.
4 | * 2. Prevent iOS and IE text size adjust after device orientation change,
5 | * without disabling user zoom.
6 | */
7 | html {
8 | font-family: sans-serif;
9 | /* 1 */
10 | -ms-text-size-adjust: 100%;
11 | /* 2 */
12 | -webkit-text-size-adjust: 100%;
13 | /* 2 */
14 | }
15 | /**
16 | * Remove default margin.
17 | */
18 | body {
19 | margin: 0;
20 | }
21 | /* HTML5 display definitions
22 | ========================================================================== */
23 | /**
24 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
25 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
26 | * and Firefox.
27 | * Correct `block` display not defined for `main` in IE 11.
28 | */
29 | article,
30 | aside,
31 | details,
32 | figcaption,
33 | figure,
34 | footer,
35 | header,
36 | hgroup,
37 | main,
38 | menu,
39 | nav,
40 | section,
41 | summary {
42 | display: block;
43 | }
44 | /**
45 | * 1. Correct `inline-block` display not defined in IE 8/9.
46 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
47 | */
48 | audio,
49 | canvas,
50 | progress,
51 | video {
52 | display: inline-block;
53 | /* 1 */
54 | vertical-align: baseline;
55 | /* 2 */
56 | }
57 | /**
58 | * Prevent modern browsers from displaying `audio` without controls.
59 | * Remove excess height in iOS 5 devices.
60 | */
61 | audio:not([controls]) {
62 | display: none;
63 | height: 0;
64 | }
65 | /**
66 | * Address `[hidden]` styling not present in IE 8/9/10.
67 | * Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
68 | */
69 | [hidden],
70 | template {
71 | display: none;
72 | }
73 | /* Links
74 | ========================================================================== */
75 | /**
76 | * Remove the gray background color from active links in IE 10.
77 | */
78 | a {
79 | background-color: transparent;
80 | }
81 | /**
82 | * Improve readability of focused elements when they are also in an
83 | * active/hover state.
84 | */
85 | a:active,
86 | a:hover {
87 | outline: 0;
88 | }
89 | /* Text-level semantics
90 | ========================================================================== */
91 | /**
92 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
93 | */
94 | abbr[title] {
95 | border-bottom: 1px dotted;
96 | }
97 | /**
98 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
99 | */
100 | b,
101 | strong {
102 | font-weight: bold;
103 | }
104 | /**
105 | * Address styling not present in Safari and Chrome.
106 | */
107 | dfn {
108 | font-style: italic;
109 | }
110 | /**
111 | * Address variable `h1` font-size and margin within `section` and `article`
112 | * contexts in Firefox 4+, Safari, and Chrome.
113 | */
114 | h1 {
115 | /* font-size: 2em; */
116 | margin: 0.67em 0;
117 | }
118 | /**
119 | * Address styling not present in IE 8/9.
120 | */
121 | mark {
122 | background: #ff0;
123 | color: #000;
124 | }
125 | /**
126 | * Address inconsistent and variable font size in all browsers.
127 | */
128 | small {
129 | font-size: 80%;
130 | }
131 | /**
132 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
133 | */
134 | sub,
135 | sup {
136 | font-size: 75%;
137 | line-height: 0;
138 | position: relative;
139 | vertical-align: baseline;
140 | }
141 | sup {
142 | top: -0.5em;
143 | }
144 | sub {
145 | bottom: -0.25em;
146 | }
147 | /* Embedded content
148 | ========================================================================== */
149 | /**
150 | * Remove border when inside `a` element in IE 8/9/10.
151 | */
152 | img {
153 | border: 0;
154 | }
155 | /**
156 | * Correct overflow not hidden in IE 9/10/11.
157 | */
158 | svg:not(:root) {
159 | overflow: hidden;
160 | }
161 | /* Grouping content
162 | ========================================================================== */
163 | /**
164 | * Address margin not present in IE 8/9 and Safari.
165 | */
166 | figure {
167 | margin: 1em 40px;
168 | }
169 | /**
170 | * Address differences between Firefox and other browsers.
171 | */
172 | hr {
173 | box-sizing: content-box;
174 | height: 0;
175 | }
176 | /**
177 | * Contain overflow in all browsers.
178 | */
179 | pre {
180 | overflow: auto;
181 | }
182 | /**
183 | * Address odd `em`-unit font size rendering in all browsers.
184 | */
185 | code,
186 | kbd,
187 | pre,
188 | samp {
189 | font-family: monospace, monospace;
190 | font-size: 1em;
191 | }
192 | /* Forms
193 | ========================================================================== */
194 | /**
195 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
196 | * styling of `select`, unless a `border` property is set.
197 | */
198 | /**
199 | * 1. Correct color not being inherited.
200 | * Known issue: affects color of disabled elements.
201 | * 2. Correct font properties not being inherited.
202 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
203 | */
204 | button,
205 | input,
206 | optgroup,
207 | select,
208 | textarea {
209 | color: inherit;
210 | /* 1 */
211 | font: inherit;
212 | /* 2 */
213 | margin: 0;
214 | /* 3 */
215 | }
216 | /**
217 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
218 | */
219 | button {
220 | overflow: visible;
221 | }
222 | /**
223 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
224 | * All other form control elements do not inherit `text-transform` values.
225 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
226 | * Correct `select` style inheritance in Firefox.
227 | */
228 | button,
229 | select {
230 | text-transform: none;
231 | }
232 | /**
233 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
234 | * and `video` controls.
235 | * 2. Correct inability to style clickable `input` types in iOS.
236 | * 3. Improve usability and consistency of cursor style between image-type
237 | * `input` and others.
238 | * 4. CUSTOM FOR WEBFLOW: Removed the input[type="submit"] selector to reduce
239 | * specificity and defer to the .w-button selector
240 | */
241 | button,
242 | html input[type="button"],
243 | input[type="reset"] {
244 | -webkit-appearance: button;
245 | /* 2 */
246 | cursor: pointer;
247 | /* 3 */
248 | }
249 | /**
250 | * Re-set default cursor for disabled elements.
251 | */
252 | button[disabled],
253 | html input[disabled] {
254 | cursor: default;
255 | }
256 | /**
257 | * Remove inner padding and border in Firefox 4+.
258 | */
259 | button::-moz-focus-inner,
260 | input::-moz-focus-inner {
261 | border: 0;
262 | padding: 0;
263 | }
264 | /**
265 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
266 | * the UA stylesheet.
267 | */
268 | input {
269 | line-height: normal;
270 | }
271 | /**
272 | * It's recommended that you don't attempt to style these elements.
273 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
274 | *
275 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
276 | * 2. Remove excess padding in IE 8/9/10.
277 | */
278 | input[type="checkbox"],
279 | input[type="radio"] {
280 | box-sizing: border-box;
281 | /* 1 */
282 | padding: 0;
283 | /* 2 */
284 | }
285 | /**
286 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
287 | * `font-size` values of the `input`, it causes the cursor style of the
288 | * decrement button to change from `default` to `text`.
289 | */
290 | input[type="number"]::-webkit-inner-spin-button,
291 | input[type="number"]::-webkit-outer-spin-button {
292 | height: auto;
293 | }
294 | /**
295 | * 1. CUSTOM FOR WEBFLOW: changed from `textfield` to `none` to normalize iOS rounded input
296 | * 2. CUSTOM FOR WEBFLOW: box-sizing: content-box rule removed
297 | * (similar to normalize.css >=4.0.0)
298 | */
299 | input[type="search"] {
300 | -webkit-appearance: none;
301 | /* 1 */
302 | }
303 | /**
304 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
305 | * Safari (but not Chrome) clips the cancel button when the search input has
306 | * padding (and `textfield` appearance).
307 | */
308 | input[type="search"]::-webkit-search-cancel-button,
309 | input[type="search"]::-webkit-search-decoration {
310 | -webkit-appearance: none;
311 | }
312 | /**
313 | * Define consistent border, margin, and padding.
314 | */
315 | fieldset {
316 | border: 1px solid #c0c0c0;
317 | margin: 0 2px;
318 | padding: 0.35em 0.625em 0.75em;
319 | }
320 | /**
321 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
322 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
323 | */
324 | legend {
325 | border: 0;
326 | /* 1 */
327 | padding: 0;
328 | /* 2 */
329 | }
330 | /**
331 | * Remove default vertical scrollbar in IE 8/9/10/11.
332 | */
333 | textarea {
334 | overflow: auto;
335 | }
336 | /**
337 | * Don't inherit the `font-weight` (applied by a rule above).
338 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
339 | */
340 | optgroup {
341 | font-weight: bold;
342 | }
343 | /* Tables
344 | ========================================================================== */
345 | /**
346 | * Remove most spacing between table cells.
347 | */
348 | table {
349 | border-collapse: collapse;
350 | border-spacing: 0;
351 | }
352 | td,
353 | th {
354 | padding: 0;
355 | }
356 |
--------------------------------------------------------------------------------
/src/client/style.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Inter ui';
3 | src: url('/fonts/Inter-UI-SemiBold.woff') format('woff');
4 | font-weight: 600;
5 | font-style: normal;
6 | }
7 | @font-face {
8 | font-family: 'Inter ui';
9 | src: url('/fonts/Inter-UI-Regular.woff') format('woff');
10 | font-weight: 400;
11 | font-style: normal;
12 | }
13 | @font-face {
14 | font-family: 'Inter ui';
15 | src: url('/fonts/Inter-UI-Medium.woff') format('woff');
16 | font-weight: 500;
17 | font-style: normal;
18 | }
19 | @font-face {
20 | font-family: 'Inter ui';
21 | src: url('/fonts/Inter-UI-Black.woff') format('woff');
22 | font-weight: 900;
23 | font-style: normal;
24 | }
25 | @font-face {
26 | font-family: 'Inter ui';
27 | src: url('/fonts/Inter-UI-Bold.woff') format('woff');
28 | font-weight: 700;
29 | font-style: normal;
30 | }
31 | @font-face {
32 | font-family: 'Inter ui';
33 | src: url('/fonts/Inter-UI-ExtraBold.woff') format('woff');
34 | font-weight: 800;
35 | font-style: normal;
36 | }
37 | @font-face {
38 | font-family: 'Regolapro';
39 | src: url('/fonts/RegolaPro-Bold.otf') format('opentype');
40 | font-weight: 700;
41 | font-style: normal;
42 | }
43 | @font-face {
44 | font-family: 'Regolapro';
45 | src: url('/fonts/RegolaPro-Regular.otf') format('opentype');
46 | font-weight: 400;
47 | font-style: normal;
48 | }
49 | @font-face {
50 | font-family: 'Regolapro';
51 | src: url('/fonts/RegolaPro-Book.otf') format('opentype');
52 | font-weight: 300;
53 | font-style: normal;
54 | }
55 | @font-face {
56 | font-family: 'Regolapro';
57 | src: url('/fonts/RegolaPro-Medium.otf') format('opentype');
58 | font-weight: 500;
59 | font-style: normal;
60 | }
61 | [v-cloak] {
62 | display: none;
63 | }
64 | .logo {
65 | position: relative;
66 | text-align: center;
67 | top: 50%;
68 | }
69 | #editor {
70 | position: absolute;
71 | top: 135px;
72 | right: 8px;
73 | width: 40%;
74 | height: 80%;
75 | visibility: visible;
76 | }
77 | #editor-controls {
78 | padding-bottom: 3px;
79 | }
80 | .CodeMirror {
81 | width: 100%;
82 | height: 100%;
83 | }
84 | .error-span {
85 | background-color: red;
86 | color: white;
87 | }
88 | body {
89 | background: white;
90 | font-family: 'Regolapro', 'Poppins', sans-serif;
91 | letter-spacing: 0.1px;
92 | margin: 0;
93 | }
94 | .ge_editor {
95 | letter-spacing: 0px;
96 | }
97 | button {
98 | letter-spacing: 0.5px;
99 | }
100 | h1 {
101 | letter-spacing: 0.5px;
102 | }
103 | a {
104 | text-decoration: none;
105 | transition: color 300ms ease-in-out;
106 | color: #006492;
107 | }
108 | a:hover {
109 | color: #black;
110 | }
111 | .w-layout-grid {
112 | display: -ms-grid;
113 | display: grid;
114 | grid-auto-columns: 1fr;
115 | -ms-grid-columns: 1fr 1fr;
116 | grid-template-columns: 1fr 1fr;
117 | -ms-grid-rows: auto auto;
118 | grid-template-rows: auto auto;
119 | grid-row-gap: 16px;
120 | grid-column-gap: 16px;
121 | }
122 | input:focus,
123 | select:focus,
124 | textarea:focus,
125 | button:focus {
126 | outline: none;
127 | }
128 |
--------------------------------------------------------------------------------
/src/components/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
About
4 |
5 | Shader Park is an open source web-based platform and community for creating real-time 3D graphics and animations using code.
6 | It integrates diverse computer graphics techniques into a unified programming interface designed for fast
7 | experimentation and live-coding.
8 |
9 | Inspired by tools and communities like P5.js, Processing, Three.js, and Shader Toy, Torin Blankensmith and
10 | Peter Whidden developed Shader Park
11 | with the intention of making emerging technology in computer graphics accessible and inclusive for artists, designers, and educators.
12 |
13 |
14 | If you enjoy using Shader Park please consider giving us a star.
15 | Core Framework
16 | Star
17 |
18 | Website
19 | Star
20 |
21 |
22 |
23 | Acknowledgments:
24 | Special thanks to the following for inspiration and guidance:
25 | Inigo Quilez, Ricardo Cabello, Andrew Palmer, Ben Fry, Casey Reas, Kyle Phillips, Reza Ali, Alex Miller, Avneesh Sarwate, Jono Brandel and Cassie Tarakajian.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
59 |
60 |
61 |
100 |
--------------------------------------------------------------------------------
/src/components/ActionBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Edit Code
5 |
6 | {{favoriteCount}}
7 | Share
8 |
9 |
10 |
11 |
12 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/components/CardModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
23 |
24 |
35 |
--------------------------------------------------------------------------------
/src/components/Error404.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | 404 Page Missing
4 |
5 | This page displays when a route is accessed that doesn't exist.
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/components/Examples.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/components/Explore.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
Featured Sculptures
9 |
10 | New Sculptures
11 |
12 |
13 |
14 |
15 |
16 |
65 |
66 |
71 |
--------------------------------------------------------------------------------
/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | SP
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Explore
14 |
15 |
Docs
16 |
Discord
17 |
New
18 |
About
19 |
Sign In
20 |
21 |
22 |
23 |
29 | Profile
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
97 |
98 |
304 |
--------------------------------------------------------------------------------
/src/components/Home.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | shader-park-core
8 |
9 | A JavaScript library for creating interactive procedural 2D and 3D shaders.
10 |
11 |
12 | Explore shader programming through a JavaScript interface without the complexity of GLSL. Quickly script shaders using a P5.js style language.
13 |
14 |
15 |
20 |
21 |
22 |
23 |
24 |
38 |
39 |
40 |
41 |
42 | Featured Sculptures ›
43 |
44 |
45 |
46 |
47 |
67 |
68 |
69 |
70 | Getting Started
71 |
72 |
73 |
74 |
75 |
76 |
77 |
92 |
93 |
94 | Featured Projects
95 | Submit a Project
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
232 |
233 |
234 |
512 |
--------------------------------------------------------------------------------
/src/components/Home3D.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/components/MainContainer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
113 |
114 |
211 |
--------------------------------------------------------------------------------
/src/components/New.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
102 |
103 |
110 |
--------------------------------------------------------------------------------
/src/components/Profile.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
12 |
13 |
14 |
15 |
111 |
112 |
--------------------------------------------------------------------------------
/src/components/Room.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/components/Sculpture.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/src/components/SculptureFeed.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | {{sculpture.title}}
11 |
by
12 |
13 | {{sculpture.username}}
14 |
15 |
16 | forked from
17 |
18 | {{sculpture.fork}}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
66 |
67 |
68 |
148 |
--------------------------------------------------------------------------------
/src/components/ShareModal.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Share
5 |
{{sculptureTitle}}
6 |
29 |
30 |
31 |
32 |
117 |
118 |
208 |
--------------------------------------------------------------------------------
/src/components/SignIn.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
73 |
80 |
--------------------------------------------------------------------------------
/src/components/SignUp.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
15 |
16 |
79 |
80 |
122 |
--------------------------------------------------------------------------------
/src/components/SpThreeVue.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
206 |
207 |
208 |
--------------------------------------------------------------------------------
/src/components/UniformGUI.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
131 |
132 |
200 |
--------------------------------------------------------------------------------
/src/dbConfig.js:
--------------------------------------------------------------------------------
1 | export const dbConfig = {
2 | apiKey: 'AIzaSyAEc1jo0NaCuSRsdKzrxDEkm6zEDqsKHIw',
3 | authDomain: 'shader-park-core.firebaseapp.com',
4 | databaseURL: 'https://shader-park-core.firebaseio.com',
5 | projectId: 'shader-park-core',
6 | storageBucket: 'shader-park-core.appspot.com',
7 | messagingSenderId: '450026358426',
8 | appId: "1:450026358426:web:3c6e10ed94e67fd3644123",
9 | measurementId: "G-6609S7GCV5"
10 | };
--------------------------------------------------------------------------------
/src/helpers/front-page-sculp1.js:
--------------------------------------------------------------------------------
1 | export function spCode2() {
2 | return `
3 | let hover = input(0, 0, 1);
4 | let click = input(0, 0, 1);
5 | let scroll = input();
6 | lightDirection(getRayDirection());
7 | metal(.4);
8 | shine(.7);
9 |
10 | let sCurve = shape((size, innerOffset) => {
11 | sphere(size);
12 | difference();
13 | let s = getSpace();
14 | displace(0.1, innerOffset, s.z);
15 | sphere(size-.03);
16 | expand(.00)
17 | })
18 |
19 |
20 | let s = getSpace();
21 | let col = vec3(0, .1, length(normal));
22 | color(col+normal*.1)
23 | rotateX((sin(time))*.04);
24 | rotateZ((sin(time))*.04);
25 | rotateY((cos(time))*.1);
26 |
27 | shape(() => {
28 | for(let i = 0; i < 3; i++) {
29 | blend(.1);
30 | // let rot = 4 * sin(time * .2) * .5 * hover;
31 | let rot = hover;
32 | rotateX(rot);
33 | rotateY(rot);
34 | rotateZ(rot);
35 | sCurve(1*(i/3)+.3, .2);
36 | }
37 | sphere(.15);
38 | })();
39 | mixGeo(nsin(time)*.22+.9 * 1-click);
40 | sphere(.8)
41 | `;
42 | }
43 |
44 | export function spCode() {
45 | //Put your Shader Park Code here
46 | return `
47 | let scroll = input();
48 | let hover = input();
49 | let click = input();
50 | //setMaxIterations(1)
51 | setStepSize(.3);
52 | lightDirection(mouse);
53 |
54 |
55 | rotateY(time * .2);
56 | let warpedSpace = warpSpace(getSpace());
57 | metal(.9);
58 | shine(1);
59 | color(1 - warpedSpace);
60 | sphere(.5 + length(warpedSpace) * .2);
61 | expand(hover * .03)
62 |
63 | // inspired by https://www.shadertoy.com/view/ttlGDf
64 | function warpSpace(p) {
65 | let t = time / 4.;
66 | rotateY(getRayDirection().y * (1 - click) * 12);
67 | p = getSpace().x*8.0*(vec3(0.5, .2, .1) + p);
68 | for(let i = 1.0; i < 3.0; i += 1.0) {
69 | p.x = p.x +hover * sin(2.0 * t + i * 1.5 * p.y) + t * 0.5;
70 | p.y = p.x + hover * cos(2.0 * t + i * 1.5 * p.x);
71 | }
72 | return 0.5 + 0.5 * cos(time + vec3(p.x, p.y, p.x) + vec3(0., 2., 4.));
73 | }
74 | `
75 | };
76 |
77 | export function spCode3() {
78 | // for mobile we keep iterations very low for improved performance
79 | return `
80 | setMaxIterations(1);
81 | backgroundColor(0, 5, 20);
82 | let scroll = input();
83 | let hover = input();
84 | let click = input();
85 | let t = time *.1+scroll;
86 | // let t = time *.01;
87 |
88 | let n = noise( vec3(0, 0, -1*t) + noise(getRayDirection() * 1 + t));
89 | displace(n*.2);
90 | let col = vec3(nsin(n*2) + ncos(n*10));
91 | color(col * 3);
92 | // metal(n);
93 | // shine(n);
94 |
95 | sphere(0.5+length(col)*.01);
96 | `;
97 | }
--------------------------------------------------------------------------------
/src/helpers/handelUnsavedChanges.js:
--------------------------------------------------------------------------------
1 |
2 | export const handelUnsavedChanges = (next, self)=> {
3 | if (Object.keys(self.$store.getters.unsavedChanges).length !== 0) {
4 | self.$modal.show('dialog', {
5 | title: 'Unsaved Changes',
6 | text: 'Are you sure you want to leave and discard changes?',
7 | buttons: [
8 | {
9 | title: 'Leave & Discard Changes', // Button title
10 | handler: () => {
11 | self.$store.commit('resetUnsavedChanges');
12 | next();
13 | self.$modal.hide('dialog')
14 | }
15 | },
16 | {
17 | title: 'Cancel',
18 | default: true,
19 | handler: () => self.$modal.hide('dialog')
20 | }]
21 | })
22 | } else {
23 | next();
24 | }
25 | }
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from 'register-service-worker'
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready () {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB'
11 | )
12 | },
13 | registered () {
14 | console.log('Service worker has been registered.')
15 | },
16 | cached () {
17 | console.log('Content has been cached for offline use.')
18 | },
19 | updatefound () {
20 | console.log('New content is downloading.')
21 | },
22 | updated () {
23 | console.log('New content is available; please refresh.');
24 | window.location.reload();
25 | },
26 | offline () {
27 | console.log('No internet connection found. App is running in offline mode.')
28 | },
29 | error (error) {
30 | console.error('Error during service worker registration:', error)
31 | }
32 | })
33 | }
34 |
--------------------------------------------------------------------------------
/src/router/routes.js:
--------------------------------------------------------------------------------
1 | import New from '../components/New.vue';
2 |
3 |
4 | // This is where you add all your site routes
5 | // Each route is set as an obect in the array
6 | // For a the most basic route just set
7 | // the path & component to load
8 |
9 | export const routes = [
10 | {
11 | path: '/explore',
12 | name: 'explore',
13 | component: () => import(/* webpackChunkName: "explore" */ '../components/Explore.vue'),
14 | meta: {
15 | title: 'Explore',
16 | }
17 | },
18 | {
19 | path: '',
20 | name: 'home',
21 | component: () => import(/* webpackChunkName: "home" */ '../components/Home.vue'),
22 | meta: {
23 | title: '',
24 | }
25 | },
26 | {
27 | path: '/examples',
28 | name: 'examples',
29 | component: () => import(/* webpackChunkName: "examples" */ '../components/Examples.vue'),
30 | props: (route) => ({embed: route.query.embed}),
31 | meta: {
32 | title: 'Examples',
33 | }
34 | },
35 | {
36 | path: '/gallery',
37 | name: 'gallery',
38 | component: () => import(/* webpackChunkName: "examples" */ '../components/Home3D.vue'),
39 | props: (route) => ({embed: route.query.embed}),
40 | meta: {
41 | title: 'Gallery',
42 | }
43 | },
44 | {
45 | path: '/new/:type',
46 | name: 'new',
47 | component: New,
48 | meta: {
49 | title: 'New Sculpture',
50 | selectedSculpture: true
51 | }
52 | },
53 | {
54 | path: '/new',
55 | name: 'new',
56 | component: New,
57 | meta: {
58 | title: 'New Sculpture',
59 | selectedSculpture: true
60 | }
61 | },
62 | {
63 | path: '/sign-in',
64 | name: 'signIn',
65 | component: () => import(/* webpackChunkName: "signin" */ '../components/SignIn.vue'),
66 | meta: {
67 | title: 'Sign In',
68 | }
69 | },
70 | {
71 | path: '/sign-up',
72 | name: 'signUp',
73 | component: () => import(/* webpackChunkName: "signup" */ '../components/SignUp.vue'),
74 | meta: {
75 | title: 'Sign Up',
76 | }
77 | },
78 | {
79 | path: '/profile',
80 | name: 'profile',
81 | component: () => import(/* webpackChunkName: "profile" */ '../components/Profile.vue'),
82 | meta: {title: 'Profile', requiresAuth: true}
83 | },
84 | {
85 | path: '/featured',
86 | name: 'featured',
87 | component: () => import(/* webpackChunkName: "home" */ '../components/Explore.vue'),
88 | meta: { title: 'Featured', requiresAuth: false }
89 | },
90 | {
91 | path: '/sculpture/:id',
92 | name: 'sculpture',
93 | component: New,
94 | props: (route) => ({
95 | example: route.query.example,
96 | embed: route.query.embed,
97 | hideEditor: route.query.hideeditor,
98 | hidePedestal: route.query.hidepedestal,
99 | clickEnabled: route.query.clickenabled
100 | }),
101 | meta: {
102 | title: 'sculpture',
103 | selectedSculpture: true
104 | }
105 | },
106 | {
107 | path: '/embed/:id',
108 | name: 'embed',
109 | component: New,
110 | props: (route) => ({
111 | example: route.query.example,
112 | embed: true,
113 | hideEditor: true,
114 | hidePedestal: true,
115 | clickEnabled: false
116 | }),
117 | meta: {
118 | title: 'embed',
119 | selectedSculpture: true
120 | }
121 | },
122 | {
123 | path: '/user/:username',
124 | name: 'user',
125 | component: () => import(/* webpackChunkName: "profile" */ '../components/Profile.vue'),
126 | meta: {
127 | title: 'user',
128 | }
129 | },
130 | {
131 | path: '/about',
132 | name: 'about',
133 | component: () => import(/* webpackChunkName: "about" */ '../components/About.vue'),
134 | meta: { title: 'About'}
135 | },
136 | {
137 | path: '/404',
138 | name: '404',
139 | component: import(/* webpackChunkName: "error" */ '../components/Error404.vue')
140 | },
141 | {path: '*', redirect: '/404'}
142 | ]
--------------------------------------------------------------------------------
/src/schema/User.js:
--------------------------------------------------------------------------------
1 | export const userSchema = {
2 | username : '',
3 | created : Date.now(),
4 | email : '',
5 | website : null,
6 | bio : null,
7 | "profile-picture" : null,
8 | favorites : [],
9 | sketches : [],
10 | followers : [],
11 | following : [],
12 | notifications : [],
13 | }
--------------------------------------------------------------------------------
/src/store/store.js:
--------------------------------------------------------------------------------
1 | import firebase from 'firebase/compat/app';
2 | import 'firebase/compat/auth';
3 |
4 | import Vue from 'vue';
5 | import Vuex from 'vuex';
6 |
7 | Vue.use(Vuex);
8 |
9 | export const store = new Vuex.Store({
10 |
11 | state: {
12 | user: null,
13 | userFavorites: {},
14 | socket: null,
15 | clickEnabled: true,
16 | currentRoom: null,
17 | initialCameraPose: null,
18 | selectedSculpture: null, // vue sculpture data
19 | currSculpture: null, // vue sculpture data for currently loaded sculpure
20 | selectedObject: null, // three.js mesh
21 | objectsToUpdate: [],
22 | objectsToRaycast: [],
23 | intersectedObject: null,
24 | currentSculptures: [],
25 | loading: false,
26 | sculpturesLoaded: false,
27 | profileBadgeCount: 0,
28 | embedded: false,
29 | canvasSize: {width: 0, height: 0},
30 | displayLogin: false,
31 | displaySignUp: false,
32 | displayCanvas: false,
33 | routeTitle: null,
34 | unsavedChanges: {},
35 | MSDFTexture: {},
36 | sculptureError: null,
37 | displayShareModal: false
38 | },
39 | getters: {
40 | userFavorites: state => {
41 | return state.userFavorites;
42 | },
43 | displayShareModal: state => {
44 | return state.displayShareModal;
45 | },
46 | getSculptureError: state => {
47 | return state.sculptureError;
48 | },
49 | displayCanvas: state => {
50 | return state.displayCanvas;
51 | },
52 | getMSDFTexture: state => {
53 | return state.MSDFTexture;
54 | },
55 | unsavedChanges: state => {
56 | return state.unsavedChanges;
57 | },
58 | routeTitle: state => {
59 | return state.routeTitle;
60 | },
61 | displayLogin: state => {
62 | return state.displayLogin;
63 | },
64 | displaySignUp: state => {
65 | return state.displaySignUp;
66 | },
67 | getUser: state => {
68 | return state.user;
69 | },
70 | selectedSculpture: state => {
71 | return state.selectedSculpture;
72 | },
73 | getCurrentSculptures: state => {
74 | return state.currentSculptures;
75 | },
76 | isAdmin: state => {
77 | return state.user && state.user.uid === 'K3lAQQTKbiTiVXlwRZouH4OrWyv1';
78 | },
79 | getProfileBadgeCount: state => {
80 | return state.profileBadgeCount;
81 | },
82 | getEmbedded: state => {
83 | return state.embedded;
84 | }
85 | },
86 | mutations: {
87 | setCurrSculpture(state, payload) {
88 | state.currSculpture = {};
89 | state.currSculpture = payload;
90 | },
91 | setUserFavorites(state, payload) {
92 | state.userFavorites = {};
93 | Object.assign(state.userFavorites, payload);
94 | },
95 | displayShareModal(state, payload) {
96 | state.displayShareModal = payload;
97 | },
98 | setSculptureError(state, payload) {
99 | state.sculptureError = payload;
100 | },
101 | setDisplayCanvas(state, payload) {
102 | state.displayCanvas = payload;
103 | },
104 | setMSDFTexture(state, payload) {
105 | state.MSDFTexture = payload;
106 | },
107 | setUnsavedChanges(state, payload) {
108 | Object.keys(payload).forEach(key => {
109 | if(payload[key]){
110 | delete state.unsavedChanges[key];
111 | } else {
112 | state.unsavedChanges[key] = payload[key];
113 | }
114 | });
115 | },
116 | resetUnsavedChanges(state) {
117 | state.unsavedChanges = {};
118 | },
119 | setClickEnabled(state, payload) {
120 | state.clickEnabled = payload;
121 | },
122 | setInitialCameraPose(state, payload) {
123 | state.initialCameraPose = payload;
124 | },
125 | setRouteTitle(state, title) {
126 | state.routeTitle = title;
127 | },
128 | displayLogin(state, payload) {
129 | state.displayLogin = payload;
130 | if (payload) {
131 | state.displaySignUp = false;
132 | }
133 | },
134 | displaySignUp(state, payload) {
135 | state.displaySignUp = payload;
136 | if (payload) {
137 | state.displayLogin = false;
138 | }
139 | },
140 | setCanvasSize(state, size) {
141 | state.canvasSize = size;
142 | },
143 | setUser: state => {
144 | state.user = firebase.auth().currentUser;
145 | },
146 | setEmbedded(state, embedded) {
147 | state.embedded = embedded;
148 | },
149 | setSelectedSculpture(state, sculpture) {
150 | state.selectedSculpture = sculpture;
151 | },
152 | setCurrentSculptures(state, payload) {
153 | state.currentSculptures = payload;
154 | },
155 | setLoading(state, payload) {
156 | state.loading = payload;
157 | },
158 | incrementProfileBadgeCount(state) {
159 | state.profileBadgeCount += 1;
160 | },
161 | setProfileBadgeCount(state, payload) {
162 | state.profileBadgeCount = payload;
163 | },
164 | sculpturesLoaded(state, payload) {
165 | state.sculpturesLoaded = payload;
166 | },
167 | updateSelectedSculpture(state, payload) {
168 | state.selectedSculpture = Object.assign(state.selectedSculpture, payload);
169 | },
170 | updateSculptureIdInScene(state, payload) {
171 | const oldId = payload.oldId;
172 | const newId = payload.newId;
173 | const obj = window.scene.getObjectByName(oldId);
174 | if(obj) {
175 | obj.name = newId;
176 | } else {
177 | console.error('no object found when updating sculpture ID ');
178 | }
179 | state.selectedSculpture.id = newId;
180 | },
181 | removeObjectFromUpdate(state, payload) {
182 | const index = state.objectsToUpdate.indexOf(payload);
183 | if (index != -1) {
184 | state.objectsToUpdate.splice(index, 1);
185 | }
186 | },
187 | removeObjectFromRaycast(state, payload) {
188 | const index = state.objectsToRaycast.indexOf(payload);
189 | if (index != -1) {
190 | state.objectsToRaycast.splice(index, 1);
191 | }
192 | },
193 | removeObjectFromSceneByName(state, name) {
194 | window.scene.remove(window.scene.getObjectByName(name));
195 | },
196 | joinRoom(state, roomName) {
197 | // state.socket.emit('joinRoom', roomName);
198 | state.currentRoom = roomName;
199 | },
200 | leaveRoom(state, roomName) {
201 | // state.socket.emit('leaveRoom', roomName);
202 | state.currentRoom = null;
203 | }
204 | },
205 | actions: {
206 | setUser: context => {
207 | context.commit('setUser');
208 | },
209 | getAllUserNames() {
210 | return firebase.database().ref(`usernames`).once('value')
211 | .then(data => data.val());
212 | },
213 | getUserIdFromUsername(context, username) {
214 | return firebase.database().ref(`usernames/${username}`).once('value')
215 | .then(data => data.val());
216 | },
217 | getUserName({getters}) {
218 | const user = getters.getUser;
219 | return firebase.database().ref(`users/${user.uid}`).once('value')
220 | .then(data => data.val().username);
221 | },
222 | setDBUser(context, payload) {
223 | let uid = payload.uid;
224 | let dbUser = payload.user;
225 | firebase.database().ref('users/' + uid).set(dbUser);
226 | firebase.database().ref('usernames/' + dbUser.username).set(uid);
227 | },
228 | async saveNewSculpture({commit, getters}, sculpture) {
229 | const user = getters.getUser;
230 | // sculpture.author = { uid: user.uid, username: user.displayName };
231 | sculpture.uid = user.uid;
232 | sculpture.username = user.displayName;
233 | sculpture.timestamp = Date.now();
234 | const idHistory = {
235 | oldId: sculpture.id || sculpture.vueId,
236 | newId: ''
237 | };
238 | delete sculpture.vueId; // remove the vueId when saving to db
239 | const sculpID = await firebase.database().ref(`sculptures`).push().key;
240 | sculpture.id = sculpID;
241 | let route = sculpture.isExample && getters.isAdmin ? 'examples' : 'sculptures';
242 | await firebase.database().ref(`${route}/${sculpID}`).update(sculpture)
243 | .catch(error => console.error(error));
244 |
245 | //update list of sculptures in user's profile
246 | await firebase.database().ref(`users/${user.uid}/sculptures`).child(sculpID).set(sculpID)
247 | .catch(error => console.error(error));
248 |
249 | idHistory.newId = sculpID;
250 |
251 | commit('updateSelectedSculpture', sculpture);
252 | commit('updateSculptureIdInScene', idHistory);
253 | commit('setLoading', false);
254 | commit('incrementProfileBadgeCount');
255 | return sculpID;
256 | },
257 | saveSculpture({commit, dispatch, getters}, sculptureObj) {
258 | return new Promise(async (resolve, reject) => {
259 | try {
260 | commit('setLoading', true);
261 | let sculpture = Object.assign({}, sculptureObj);
262 | delete sculpture.sculpture; //remove the three.js 3d object
263 |
264 | console.log('saving sculpture');
265 | const user = getters.getUser;
266 | if(!user) {
267 | console.error('Tried to Save Sculpture when a User is not logged in');
268 | reject('Tried to Save Sculpture when a User is not logged in');
269 | }
270 |
271 | if (!sculpture.id || sculpture.id === sculpture.vueId) {
272 | console.log('saving new sculpture');
273 | resolve(dispatch('saveNewSculpture', sculpture));
274 | } else {
275 | if (sculpture.uid === user.uid || getters.isAdmin) { // update existing sculpture
276 | let route = sculpture.isExample && getters.isAdmin ? 'examples' : 'sculptures'; //must be admin to update example
277 | delete sculpture.vueId; // remove the three.js 3d object
278 |
279 | resolve(firebase.database().ref(`${route}/${sculpture.id}`).update(sculpture).then(() => {
280 | commit('setLoading', false);
281 | }));
282 | } else { // Save as a fork
283 | console.log('save as fork');
284 | const newForkCount = sculpture.forks += 1;
285 | //update existing sculpture fork count
286 | let route = sculpture.isExample? 'examples' : 'sculptures'; //they don't have to be an admin to fork
287 | await firebase.database().ref(`${route}/${sculpture.id}/forks`).set(newForkCount);
288 | sculpture.isExample = false; //fork isn't an example
289 | Object.assign(sculpture, {
290 | forks: 0,
291 | uid: user.uid,
292 | username: user.displayName,
293 | fork: sculpture.id,
294 | forkedSculptureTitle: sculpture.title,
295 | featured: false,
296 | isExample: false,
297 | views: 0,
298 | favorites: 0,
299 | comments: 0
300 | });
301 | // sculpture.forks = 0;
302 | // sculpture.uid = user.uid;
303 | // sculpture.author = {uid: user.uid, username: user.displayName}; //new author
304 | // sculpture.fork = sculpture.id; //save the id of the original sculpture
305 | const fork = {
306 | uid: user.uid,
307 | username: user.displayName,
308 | timestamp: Date.now(),
309 | shaderSourceHistory: sculpture.shaderSource,
310 | rootId: sculpture.id
311 | }
312 | let newId = await dispatch('saveNewSculpture', sculpture);
313 | fork['newSculptureId'] = newId;
314 | resolve(firebase.database().ref(`forks`).push(fork).then(() => {
315 | commit('setLoading', false);
316 | }));
317 | }
318 | }
319 | } catch(e) {
320 | console.error(e);
321 | reject(e);
322 | }
323 | });
324 | },
325 | removeSelectedSculptureFromScene({commit, getters}) {
326 | let selectedSculpture = getters.selectedSculpture;
327 | commit('removeObjectFromUpdate', selectedSculpture.sculpture);
328 | commit('removeObjectFromRaycast', selectedSculpture.sculpture.mesh);
329 | commit('removeObjectFromSceneByName', selectedSculpture.id);
330 | },
331 | deleteSculpture({commit, getters, dispatch}, sculpture) {
332 | commit('setLoading', true);
333 | const user = getters.getUser;
334 | if (sculpture.uid === user.uid) {
335 | let route = sculpture.isExample && getters.isAdmin ? 'examples' : 'sculptures'; //must be admin to update example
336 | if(sculpture.fork) {
337 | firebase.database().ref('forks').orderByChild('newSculptureId').equalTo(sculpture.id).once('value').then(data => {
338 | let fork = data.val();
339 | if(fork) {
340 | let forkId = Object.keys(fork)[0];
341 | let rootSculptureId = fork[forkId].rootId;
342 | dispatch('fetchSculpture', {id: rootSculptureId, isExample: sculpture.isExample}).then((sculptureToUpdateForkCount) => {
343 | let route = sculptureToUpdateForkCount.isExample? 'examples' : 'sculptures'; //must be admin to update example
344 | sculptureToUpdateForkCount.forks -= 1;
345 | firebase.database().ref(`${route}/${sculptureToUpdateForkCount.id}`).update(sculptureToUpdateForkCount)
346 | .catch(error => console.error(error));
347 | });
348 | //delete fork
349 | firebase.database().ref(`forks/${forkId}`).remove().catch(error => console.error(error));
350 | }
351 | });
352 | }
353 | firebase.database().ref(`${route}/${sculpture.id}`).remove().catch(error => console.error(error));
354 | firebase.database().ref(`users/${user.uid}/sculptures/${sculpture.id}`).remove().then(() => {
355 | commit('setLoading', false);
356 | }).catch(error => console.error(error));
357 |
358 | } else {
359 | console.error('Tried to delete another user\'s sculpture');
360 | }
361 | },
362 | fetchUserSculptures({commit, getters}, username) {
363 | commit('setLoading', true);
364 | // const userId = uid || getters.getUser.uid;
365 |
366 | let route = 'sculptures';
367 | if(getters.isAdmin) {
368 | route = 'examples';
369 | }
370 |
371 | return firebase.database().ref(route).orderByChild('username').equalTo(username).once('value').then(data => {
372 | const sculptures = data.val();
373 | if(sculptures) {
374 | return Object.keys(sculptures).map(key => sculptures[key]);
375 | }
376 | return [];
377 | }).catch(error => console.error(error));
378 |
379 | // return firebase.database().ref(`${route}/${userId}`).once('value').then(data => {
380 | // commit('setLoading', false);
381 | // return data.val();
382 | // })
383 | // .catch(error => console.log(error));
384 | },
385 | fetchSculpture({commit, getters}, payload) {
386 | if (!payload.id) {
387 | console.error('No id passed to fetch sculpture');
388 | return;
389 | }
390 | commit('setLoading', true);
391 | const reference = payload.example ? 'examples/': 'sculptures/';
392 | return firebase.database().ref(`${reference}/${payload.id}`).once('value')
393 | .then(data => {
394 | commit('setLoading', false);
395 | return data.val();
396 | })
397 | .catch(error => console.log(error));
398 |
399 | // return firebase.database().ref(`${reference}`).orderByChild(payload.id).limitToLast(1).once('value')
400 | // .then(data => {
401 | // commit('setLoading', true);
402 | // //ends up getting the user's entire profile
403 | // const userSculpts = data.val();
404 | // const keys = Object.keys(userSculpts);
405 | // if (userSculpts && keys.length > 0) {
406 | // commit('setLoading', false);
407 | // return userSculpts[keys[0]][payload.id];
408 | // }
409 | // commit('setLoading', false);
410 | // return null;
411 | // })
412 | // .catch(error => console.log(error));
413 | },
414 | fetchSculptures({commit, getters}, reference) {
415 | commit('setLoading', true);
416 | const user = getters.getUser;
417 | return firebase.database().ref(reference).once('value').then(data => {
418 | const sculptures = data.val();
419 | let output = Object.keys(sculptures).map(key => sculptures[key]);
420 | // let output = [];
421 | // Object.keys(sculptures)
422 | // .forEach(key => {
423 | // Object.keys(sculptures[key]).forEach(sculptureKey => {
424 | // const sculpture = sculptures[key][sculptureKey];
425 | // output.push(sculpture);
426 | // })
427 | // });
428 | commit('setLoading', false);
429 | return output;
430 | })
431 | .catch(error => console.log(error));
432 | },
433 | fetchFeaturedSculptures({commit},) {
434 | commit('setLoading', true);
435 | return firebase.database().ref('sculptures').orderByChild("featured").equalTo(true).once('value').then(data => {
436 | const sculptures = data.val();
437 | let output = Object.keys(sculptures).map(key => sculptures[key]);
438 | commit('setLoading', false);
439 | return output;
440 | })
441 | .catch(error => console.log(error));
442 | },
443 | fetchAllSculptures({dispatch}) {
444 | return dispatch('fetchSculptures', 'sculptures');
445 | },
446 | fetchExampleSculptures({dispatch}) {
447 | return dispatch('fetchSculptures', 'examples');
448 | },
449 | fetchForks() {
450 | return firebase.database().ref('/forks').once('value').then(data => data.val());
451 | },
452 | favorite({commit, getters}, {sculpture, favorited}) {
453 | return new Promise(async (resolve, reject) => {
454 | commit('setLoading', true);
455 |
456 | let vueXUserFavorites = getters.userFavorites;
457 | const user = getters.getUser;
458 | if(!user) {
459 | console.error('Tried to favorite Sculpture when a User is not logged in');
460 | reject('Tried to favorite Sculpture when a User is not logged in');
461 | }
462 | let route = sculpture.isExample? 'examples' : 'sculptures';
463 |
464 | // Update Favorite Count
465 | await firebase.database().ref(`${route}/${sculpture.id}/favorites`).transaction((currValue) => {
466 | let newFavCount;
467 | if(favorited) {
468 | newFavCount = (currValue || 0) + 1;
469 | } else {
470 | newFavCount = Math.max((currValue || 0) - 1, 0);
471 | }
472 | sculpture.favorites = newFavCount;
473 | commit('setCurrSculpture', sculpture);
474 | return newFavCount;
475 | }).catch(error => console.error(error));
476 |
477 |
478 | // Save, or Remove favorite
479 | let time = Date.now();
480 | let userPath = `users/${user.uid}/favorites/${sculpture.id}`;
481 | if(favorited) {
482 | let favorite = {
483 | uid: user.uid,
484 | timestamp: time,
485 | sculptureId: sculpture.id,
486 | }
487 | const favoriteId = await firebase.database().ref(`favorites/`).push(favorite).key;
488 | await firebase.database().ref(userPath).set(favoriteId).catch(error => console.error(error));
489 | //make sure userFavorites is a dictionary
490 | if(!(vueXUserFavorites && vueXUserFavorites.constructor === Object)) {
491 | vueXUserFavorites = {};
492 | }
493 | vueXUserFavorites[sculpture.id] = favoriteId;
494 |
495 | store.commit('setUserFavorites', vueXUserFavorites);
496 | } else {
497 | let favoriteObj = await firebase.database().ref(userPath).once('value');
498 | let favoriteId = favoriteObj.val();
499 | delete vueXUserFavorites[sculpture.id];
500 | store.commit('setUserFavorites', vueXUserFavorites);
501 | await firebase.database().ref(userPath).remove().catch(error => console.error(error));
502 | await firebase.database().ref(`favorites/${favoriteId}`).remove().catch(error => console.error(error));
503 | }
504 |
505 | commit('setLoading', false);
506 | resolve();
507 | });
508 | },
509 | fetchUserFavorites({commit, getters}, uid) {
510 | return new Promise(async (resolve, reject) => {
511 | const user = getters.getUser;
512 | if(!user && !uid) {
513 | return;
514 | }
515 | if(user) {
516 | uid = user.uid
517 | }
518 | try {
519 | let favoritesObj = await firebase.database().ref(`users/${uid}/favorites`).once('value');
520 | commit('setUserFavorites', favoritesObj.val());
521 | resolve();
522 | } catch(e) {
523 | console.error(e);
524 | reject(e);
525 | }
526 | })
527 | }
528 | }
529 | });
--------------------------------------------------------------------------------
/src/threejs-sculpture/SculptureN.js:
--------------------------------------------------------------------------------
1 | import { BoxGeometry, MeshBasicMaterial, Color, Mesh, } from 'three';
2 |
3 | import {createPedestalEdges} from './create-pedestal-edges.js'
4 |
5 | import {sculptToThreeJSMaterial, sculptToThreeJSMesh, glslToThreeJSMaterial, glslToThreeJSMesh} from 'shader-park-core';
6 | import {defaultFragSourceGLSL} from 'shader-park-core';
7 |
8 | export class Sculpture {
9 | constructor(isGlsl, source, msdfTexture) {
10 | this.uniformsToExclude = { 'sculptureCenter': 0, 'msdf': 0, 'opacity': 0, 'time': 0, 'stepSize': 0, '_scale' : 1, 'resolution': 0};
11 | this.IsGLSL = isGlsl;
12 | this.payload = { msdfTexture}
13 | this.source = source;
14 | this.compileError = null;
15 | if (isGlsl) {
16 | try {
17 | this.mesh = glslToThreeJSMesh(source, this.payload);
18 | } catch(error) {
19 | console.error(error);
20 | this.mesh = glslToThreeJSMesh(defaultFragSourceGLSL, this.payload);
21 | this.compileError = error;
22 | // throw(e);
23 | }
24 |
25 | } else {
26 | try {
27 | this.mesh = sculptToThreeJSMesh(source, this.payload);
28 | } catch (error) {
29 | console.error(error);
30 | this.mesh = sculptToThreeJSMesh('sphere(0.5);', this.payload);
31 | this.compileError = error;
32 |
33 | }
34 | this.uniforms = this.mesh.material.uniformDescriptions;
35 | this.uniforms = this.uniforms.filter(uniform => !(uniform.name in this.uniformsToExclude))
36 | }
37 | const pedestalGeom = new BoxGeometry(2, 1, 2);
38 | this.opacity = 0.0;
39 | this.stepSize = 0.8;
40 | const pedestalMat = new MeshBasicMaterial({ color: new Color(0.95, 0.95, 0.95), transparent: true, opacity: this.opacity });
41 | this.pedestal = new Mesh(pedestalGeom, pedestalMat);
42 | this.sepBuffer = 0.05; // Small gap between sculpture and pedestal prevents z-fighting
43 | this.pedestal.position.set(0, -1.5-this.sepBuffer, 0);
44 | this.mesh.add(this.pedestal);
45 | this.pedestalEdges = createPedestalEdges(2, 1);
46 | this.pedestalEdges.position.set(0, -1.5-this.sepBuffer, 0);
47 | // this.mesh.add(this.pedestalEdges);
48 | this.selected = false;
49 | this.setOpacity(0.0);
50 | }
51 |
52 | setMSDFTexture(texture) {
53 | // this.MSDFTexture = texture;
54 | this.payload.msdfTexture = texture;
55 | // this.refreshMaterial();
56 | }
57 |
58 | selectedSculpture(selected) {
59 | if(!this.pedestal.visible) {
60 | return;
61 | }
62 | this.mesh.remove(this.pedestalEdges);
63 | if (selected) {
64 | this.pedestalEdges = createPedestalEdges(2, 1, 0.015);
65 | this.pedestalEdges.position.set(0, -1.5-this.sepBuffer, 0);
66 | this.mesh.add(this.pedestalEdges);
67 | } else {
68 | this.pedestalEdges = createPedestalEdges(2, 1);
69 | this.pedestalEdges.position.set(0, -1.5-this.sepBuffer, 0);
70 | this.mesh.add(this.pedestalEdges);
71 | }
72 | this.selected = selected;
73 | }
74 |
75 | setOpacity(value) {
76 | this.opacity = value;
77 | this.mesh.visible = value !== 0.0;
78 | this.pedestal.material.opacity = this.opacity;
79 | }
80 |
81 | refreshMaterial(newSource) {
82 | if (newSource) {
83 | this.source = newSource;
84 | }
85 | if (this.IsGLSL) {
86 | try {
87 | this.mesh.material = glslToThreeJSMaterial(this.source, this.payload);
88 | } catch(e) {
89 | console.error(e);
90 | throw(e)
91 | }
92 |
93 | } else {
94 | try {
95 | this.mesh.material = sculptToThreeJSMaterial(this.source, this.payload);
96 | } catch(e) {
97 | throw(e);
98 |
99 | }
100 | this.uniforms = this.mesh.material.uniformDescriptions;
101 | this.uniforms = this.uniforms.filter(uniform => !(uniform.name in this.uniformsToExclude))
102 | }
103 | }
104 |
105 | update(uniforms) {
106 | this.mesh.material.uniforms['opacity'].value = this.opacity;
107 | this.mesh.material.uniforms['msdf'].value = this.payload.msdfTexture;
108 | uniforms.forEach(uniform => {
109 | if(uniform && uniform.name) {
110 | this.mesh.material.uniforms[uniform.name].value = uniform.value;
111 | }
112 | });
113 | }
114 | }
115 |
116 |
--------------------------------------------------------------------------------
/src/threejs-sculpture/create-pedestal-edges.js:
--------------------------------------------------------------------------------
1 | import { BoxGeometry, MeshBasicMaterial, Color, Mesh, Group} from 'three';
2 |
3 | /**
4 | * Creates thin edges for a pedestal given its dimensions
5 | * @param pedSize width and depth of the pedestal. The same value is
6 | * used for both because they are square
7 | * @param pedHeight height of the pedestal
8 | * @todo these could change color/size to represent selection?
9 | * Add ability to set all their colors with a single call
10 | * Could be made into class
11 | */
12 |
13 | export function createPedestalEdges(pedSize, pedHeight, size = 0.005) {
14 | const edgeSize = pedSize * size;
15 | const longEdgeGeom =
16 | new BoxGeometry(edgeSize, edgeSize, pedSize + 1.0 * edgeSize);
17 | const shortEdgeGeomVertical =
18 | new BoxGeometry(edgeSize, pedHeight, edgeSize);
19 | const shortEdgeGeomHorizontal =
20 | new BoxGeometry(pedSize, edgeSize, edgeSize);
21 | const edgeMat =
22 | new MeshBasicMaterial({color: new Color(1.0, 1.0, 1.0)});
23 | const edgeGroup = new Group();
24 |
25 | const longUL = new Mesh(longEdgeGeom, edgeMat);
26 | longUL.position.x -= pedSize * 0.5;
27 | longUL.position.y += pedHeight * 0.5;
28 | edgeGroup.add(longUL);
29 |
30 | const longUR = new Mesh(longEdgeGeom, edgeMat);
31 | longUR.position.x += pedSize * 0.5;
32 | longUR.position.y += pedHeight * 0.5;
33 | edgeGroup.add(longUR);
34 |
35 | const longBL = new Mesh(longEdgeGeom, edgeMat);
36 | longBL.position.x -= pedSize * 0.5;
37 | longBL.position.y -= pedHeight * 0.5;
38 | edgeGroup.add(longBL);
39 |
40 | const longBR = new Mesh(longEdgeGeom, edgeMat);
41 | longBR.position.x += pedSize * 0.5;
42 | longBR.position.y -= pedHeight * 0.5;
43 | edgeGroup.add(longBR);
44 |
45 | const shortUF = new Mesh(shortEdgeGeomHorizontal, edgeMat);
46 | shortUF.position.z += pedSize * 0.5;
47 | shortUF.position.y += pedHeight * 0.5;
48 | edgeGroup.add(shortUF);
49 |
50 | const shortUB = new Mesh(shortEdgeGeomHorizontal, edgeMat);
51 | shortUB.position.z -= pedSize * 0.5;
52 | shortUB.position.y += pedHeight * 0.5;
53 | edgeGroup.add(shortUB);
54 |
55 | const shortLF = new Mesh(shortEdgeGeomVertical, edgeMat);
56 | shortLF.position.x -= pedSize * 0.5;
57 | shortLF.position.z += pedSize * 0.5;
58 | edgeGroup.add(shortLF);
59 |
60 | const shortRF = new Mesh(shortEdgeGeomVertical, edgeMat);
61 | shortRF.position.x += pedSize * 0.5;
62 | shortRF.position.z += pedSize * 0.5;
63 | edgeGroup.add(shortRF);
64 |
65 | const shortLB = new Mesh(shortEdgeGeomVertical, edgeMat);
66 | shortLB.position.x -= pedSize * 0.5;
67 | shortLB.position.z -= pedSize * 0.5;
68 | edgeGroup.add(shortLB);
69 |
70 | const shortRB = new Mesh(shortEdgeGeomVertical, edgeMat);
71 | shortRB.position.x += pedSize * 0.5;
72 | shortRB.position.z -= pedSize * 0.5;
73 | edgeGroup.add(shortRB);
74 |
75 | const shortBF = new Mesh(shortEdgeGeomHorizontal, edgeMat);
76 | shortBF.position.z += pedSize * 0.5;
77 | shortBF.position.y -= pedHeight * 0.5;
78 | edgeGroup.add(shortBF);
79 |
80 | const shortBB = new Mesh(shortEdgeGeomHorizontal, edgeMat);
81 | shortBB.position.z -= pedSize * 0.5;
82 | shortBB.position.y -= pedHeight * 0.5;
83 | edgeGroup.add(shortBB);
84 |
85 | return edgeGroup;
86 | }
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | publicPath: '/',
3 | pwa: {
4 | workboxOptions: {
5 | skipWaiting: true,
6 | clientsClaim: true,
7 | exclude: ['_redirects'],
8 | runtimeCaching: [
9 | {
10 | // Use the NetworkFirst strategy for HTML files
11 | urlPattern: /index\.html/,
12 | handler: 'NetworkFirst',
13 | options: {
14 | networkTimeoutSeconds: 20,
15 | cacheName: 'html-cache',
16 | },
17 | },
18 | {
19 | // Use the CacheFirst strategy for other static assets
20 | urlPattern: /\.(?:js|css|png|jpg|jpeg|svg)$/,
21 | handler: 'CacheFirst',
22 | options: {
23 | cacheName: 'static-assets',
24 | expiration: {
25 | maxEntries: 50,
26 | maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
27 | },
28 | },
29 | },
30 | {
31 | // Don't cache requests to Firebase or other real-time APIs
32 | urlPattern: /^https:\/\/(www\.)?firebaseio\.com/,
33 | handler: 'NetworkOnly',
34 | },
35 | ],
36 | },
37 | },
38 | configureWebpack: {
39 | resolve: {
40 | mainFields: ['module', 'browser', 'main']
41 | }
42 | }
43 | };
44 |
--------------------------------------------------------------------------------