From 1bfba591eacd7e812f1c078edf7cbb85e401f33d Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Mon, 26 Jul 2021 22:43:51 +0200 Subject: [PATCH 01/26] initial scrappy integration --- app/web/public/demo-worker.js | 609 ++++++++++++++++++ .../src/helpers/cadPackages/CSGToBuffers.js | 106 +++ .../helpers/cadPackages/jsCadController.ts | 102 ++- app/web/src/helpers/hooks/useIdeState.ts | 26 +- 4 files changed, 839 insertions(+), 4 deletions(-) create mode 100644 app/web/public/demo-worker.js create mode 100644 app/web/src/helpers/cadPackages/CSGToBuffers.js diff --git a/app/web/public/demo-worker.js b/app/web/public/demo-worker.js new file mode 100644 index 0000000..4833ca6 --- /dev/null +++ b/app/web/public/demo-worker.js @@ -0,0 +1,609 @@ +(function(f) { + if (typeof exports === "object" && typeof module !== "undefined") { + module.exports = f() + } else if (typeof define === "function" && define.amd) { + define([], f) + } else { + var g; + if (typeof window !== "undefined") { + g = window + } else if (typeof global !== "undefined") { + g = global + } else if (typeof self !== "undefined") { + g = self + } else { + g = this + } + g.jscadWorker = f() + } +})(function() { +// multi purpose module + + + +const setPoints = (points, p, i)=>{ + points[i++] = p[0] + points[i++] = p[1] + points[i++] = p[2] || 0 +} + +function CSG2Vertices(csg){ + let idx = 0 + + let vLen = 0, iLen = 0 + for (let poly of csg.polygons){ + let len = poly.vertices.length + vLen += len *3 + iLen += 3 * (len-2) + } + const vertices = new Float32Array(vLen) + const indices = vLen > 65535 ? new Uint32Array(iLen) : new Uint16Array(iLen) + + let vertOffset = 0 + let indOffset = 0 + let posOffset = 0 + let first = 0 + for (let poly of csg.polygons){ + let arr = poly.vertices + let len = arr.length + first = posOffset + vertices.set(arr[0], vertOffset) + vertOffset +=3 + vertices.set(arr[1], vertOffset) + vertOffset +=3 + posOffset +=2 + for(let i=2; isetPoints(vertices, p, idx * 3 )) + + if(csg.isClosed){ + setPoints(vertices, csg.points[0], vertices.length - 3 ) + } + return {vertices, type:'line'} +} + +function CSG2LineSegmentsVertices(csg){ + let vLen = csg.sides.length * 6 + + var vertices = new Float32Array(vLen) + csg.sides.forEach((side,idx)=>{ + let i = idx * 6 + setPoints(vertices, side[0], i) + setPoints(vertices, side[1], i+3) + }) + return {vertices, type:'lines'} + +} + +function CSGCached(func, data, cacheKey, transferable){ + cacheKey = cacheKey || data + + let geo = CSGToBuffers.cache.get(cacheKey) + if(geo) return geo + + geo = func(data) + + // fill transferable array for postMessage optimization + if(transferable){ + const {vertices, indices} = geo + transferable.push(vertices) + if(indices) transferable.push(indices) + } + + CSGToBuffers.cache.set(cacheKey, geo) + return geo +} + +function CSGToBuffers(csg, transferable){ + let obj + + if(csg.polygons) obj = CSGCached(CSG2Vertices,csg,csg.polygons, transferable) + if(csg.sides && !csg.points) obj = CSGCached(CSG2LineSegmentsVertices,csg,csg.sides, transferable) + if(csg.points) obj = CSGCached(CSG2LineVertices,csg,csg.points, transferable) + + return obj +} +CSGToBuffers.clearCache = ()=>{CSGToBuffers.cache = new WeakMap()} +CSGToBuffers.clearCache() + + + + +let workerBaseURI + +function require(url){ + url = require.alias[url] || url + if(url[0] != '/' && url.substr(0,2) != './' && url.substr(0,4) != 'http') url = 'https://unpkg.com/'+url + let exports=require.cache[url]; //get from cache + if (!exports) { //not cached + let module = requireModule(url) + require.cache[url] = exports = module.exports; //cache obj exported by module + } + return exports; //require returns object exported by module +} + +function requireFile(url){ + try{ + let X=new XMLHttpRequest(); + X.open("GET", new URL(url,workerBaseURI), 0); // sync + X.send(); + if (X.status && X.status !== 200) throw new Error(X.statusText); + return X.responseText; + }catch(e){ + console.log('problem loading url ',url,'base',workerBaseURI,' error:',e.message) + throw e + } +} + +function requireModule(url, source){ + try { + const exports={}; + if(!source) source = requireFile(url) + const module = { id: url, uri: url, exports:exports, source }; //according to node.js modules + // fix, add comment to show source on Chrome Dev Tools + source="//@ sourceURL="+url+"\n" + source; + //------ + const anonFn = new Function("require", "exports", "module", source); //create a Fn with module code, and 3 params: require, exports & module + anonFn(require, exports, module); // call the Fn, Execute the module + return module + } catch (err) { + console.error("Error loading module "+url, err.message); + throw err; + } +} + +require.cache = {} +require.alias = {} + + +const initCanvas = (canvas, callback)=>{ + + // convert HTML events (mouse movement) to viewer changes + let lastX = 0 + let lastY = 0 + + let pointerDown = false + + const moveHandler = (ev) => { + if(!pointerDown) return + const cmd = { + worker: 'render', + dx: lastX - ev.pageX, + dy: ev.pageY - lastY + } + + const shiftKey = (ev.shiftKey === true) || (ev.touches && ev.touches.length > 2) + cmd.action = shiftKey ? 'pan':'rotate' + callback(cmd) + + lastX = ev.pageX + lastY = ev.pageY + + ev.preventDefault() + } + const downHandler = (ev) => { + pointerDown = true + lastX = ev.pageX + lastY = ev.pageY + canvas.setPointerCapture(ev.pointerId) + ev.preventDefault() + } + + const upHandler = (ev) => { + pointerDown = false + canvas.releasePointerCapture(ev.pointerId) + ev.preventDefault() + } + + const wheelHandler = (ev) => { + callback({action:'zoom', dy:ev.deltaY, worker: 'render'}) + ev.preventDefault() + } + + canvas.onpointermove = moveHandler + canvas.onpointerdown = downHandler + canvas.onpointerup = upHandler + canvas.onwheel = wheelHandler +} + +const cmdHandler = (handlers)=>(cmd)=>{ + const fn = handlers[cmd.action] + if (!fn) throw new Error('no handler for type: ' + cmd.action) + fn(cmd); +} + + + + + + + + + +const makeScriptWorker = ({callback, convertToSolids})=>{ + let workerBaseURI, onInit + + function runMain(params={}){ + console.log('runMain'); + let time = Date.now() + let solids = main(params) + let solidsTime = Date.now() - time + scriptStats = `generate solids ${solidsTime}ms` + + let transfer = [] + if(convertToSolids === 'buffers'){ + CSGToBuffers.clearCache() + entities = solids.map((csg)=>CSGToBuffers(csg, transfer)) + }else if(convertToSolids === 'regl'){ + const { entitiesFromSolids } = require('@jscad/regl-renderer') + time = Date.now() + entities = entitiesFromSolids({}, solids) + scriptStats += ` convert to entities ${Date.now()-time}ms` + }else{ + entities = solids + } + callback({action:'entities', worker:'render', entities, scriptStats}, transfer) + } + + let initialized = false + const handlers = { + runScript: ({script,url, params={}})=>{ + if(!initialized){ + onInit = ()=>handlers.runScript({script,url, params}) + } + let script_module = requireModule(url,script) + main = script_module.exports.main + let gp = script_module.exports.getParameterDefinitions + if(gp){ + callback({action:'parameterDefinitions', worker:'main', data:gp()}) + } + runMain(params) + }, + updateParams: ({params={}})=>{ + runMain(params) + }, + init: (params)=>{ + let {baseURI, alias=[]} = params + if(!baseURI && typeof document != 'undefined' && document.baseURI){ + baseURI = document.baseURI + } + + if(baseURI) workerBaseURI = baseURI.toString() + + alias.forEach(arr=>{ + let [orig, ...aliases] = arr + aliases.forEach(a=>{ + require.alias[a] = orig + if(a.toLowerCase().substr(-3)!=='.js') require.alias[a+'.js'] = orig + }) + }) + initialized = true + if(onInit) onInit() + }, + } + + return { + // called from outside to pass mesasges into worker + postMessage: cmdHandler(handlers), + } +} + + + + + + + + + + + + + + +/** Make render worker */ + +const makeRenderWorker = ()=>{ +let perspectiveCamera + const state = {} + + const rotateSpeed = 0.002 + const panSpeed = 1 + const zoomSpeed = 0.08 + let rotateDelta = [0, 0] + let panDelta = [0, 0] + let zoomDelta = 0 + let updateRender = true + let orbitControls, renderOptions, gridOptions, axisOptions, renderer + + let entities = [] + + function createContext (canvas, contextAttributes) { + function get (type) { + try { + return {gl:canvas.getContext(type, contextAttributes), type} + } catch (e) { + return null + } + } + return ( + get('webgl2') || + get('webgl') || + get('experimental-webgl') || + get('webgl-experimental') + ) + } + + const startRenderer = ({canvas, cameraPosition, cameraTarget, axis={}, grid={}})=>{ + const { prepareRender, drawCommands, cameras, controls } = require('@jscad/regl-renderer') + + perspectiveCamera = cameras.perspective + orbitControls = controls.orbit + + state.canvas = canvas + state.camera = Object.assign({}, perspectiveCamera.defaults) + if(cameraPosition) state.camera.position = cameraPosition + if(cameraTarget) state.camera.target = cameraTarget + + resize({ width:canvas.width, height:canvas.height }) + + state.controls = orbitControls.defaults + + const {gl, type} = createContext(canvas) + // prepare the renderer + const setupOptions = { + glOptions: {gl} + } + if(type == 'webgl'){ + setupOptions.glOptions.optionalExtensions = ['oes_element_index_uint'] + } + renderer = prepareRender(setupOptions) + + gridOptions = { + visuals: { + drawCmd: 'drawGrid', + show: grid.show || grid.show === undefined , + color: grid.color || [0, 0, 0, 1], + subColor: grid.subColor || [0, 0, 1, 0.5], + fadeOut: false, + transparent: true + }, + size: grid.size || [200, 200], + ticks: grid.ticks || [10, 1] + } + + axisOptions = { + visuals: { + drawCmd: 'drawAxis', + show: axis.show || axis.show === undefined + }, + size: axis.size || 100, + } + + // assemble the options for rendering + renderOptions = { + camera: state.camera, + drawCommands: { + drawAxis: drawCommands.drawAxis, + drawGrid: drawCommands.drawGrid, + drawLines: drawCommands.drawLines, + drawMesh: drawCommands.drawMesh + }, + // define the visual content + entities: [ + gridOptions, + axisOptions, + ...entities + ] + } + // the heart of rendering, as themes, controls, etc change + + updateView() + } + + let renderTimer + const tmFunc = typeof requestAnimationFrame === 'undefined' ? setTimeout : requestAnimationFrame + + function updateView(delay=8){ + if(renderTimer || !renderer) return + renderTimer = tmFunc(updateAndRender,delay) + } + + const doRotatePanZoom = () => { + + if (rotateDelta[0] || rotateDelta[1]) { + const updated = orbitControls.rotate({ controls: state.controls, camera: state.camera, speed: rotateSpeed }, rotateDelta) + state.controls = { ...state.controls, ...updated.controls } + rotateDelta = [0, 0] + } + + if (panDelta[0] || panDelta[1]) { + const updated = orbitControls.pan({ controls:state.controls, camera:state.camera, speed: panSpeed }, panDelta) + state.controls = { ...state.controls, ...updated.controls } + panDelta = [0, 0] + state.camera.position = updated.camera.position + state.camera.target = updated.camera.target + } + + if (zoomDelta) { + const updated = orbitControls.zoom({ controls:state.controls, camera:state.camera, speed: zoomSpeed }, zoomDelta) + state.controls = { ...state.controls, ...updated.controls } + zoomDelta = 0 + } + } + + const updateAndRender = (timestamp) => { + renderTimer = null + doRotatePanZoom() + + const updates = orbitControls.update({ controls: state.controls, camera: state.camera }) + state.controls = { ...state.controls, ...updates.controls } + if(state.controls.changed) updateView(16) // for elasticity in rotate / zoom + + state.camera.position = updates.camera.position + perspectiveCamera.update(state.camera) + renderOptions.entities = [ + gridOptions, + axisOptions, + ...entities + ] + let time = Date.now() + renderer(renderOptions) + if(updateRender){ + console.log(updateRender, ' first render', Date.now()-time); + updateRender = ''; + } + } + + function resize({width,height}){ + state.canvas.width = width + state.canvas.height = height + perspectiveCamera.setProjection(state.camera, state.camera, { width, height }) + perspectiveCamera.update(state.camera, state.camera) + updateView() + } + + const handlers = { + pan: ({dx,dy})=>{ + panDelta[0] += dx + panDelta[1] += dy + updateView() + }, + rotate: ({dx,dy})=>{ + rotateDelta[0] -= dx + rotateDelta[1] -= dy + updateView() + }, + zoom: ({dy})=>{ + zoomDelta += dy + updateView() + }, + resize, + entities: (params)=>{ + entities = params.entities + updateRender = params.scriptStats + updateView() + }, + init: (params)=>{ + if(params.canvas) startRenderer(params) + initialized = true + }, + } + + return { + // called from outside to pass mesasges into worker + postMessage: cmdHandler(handlers), + } +} + + + + + + + + + + +return (params)=>{ + let { canvas, baseURI=(typeof document === 'undefined') ? '':document.location.toString(), scope='main', renderInWorker, render, callback=()=>{}, scriptUrl='demo-worker.js', alias, convertToSolids=false } = params + // by default 'render' messages go outside of this instance (result of modeling) + let sendToRender = callback + let scriptWorker, renderWorker + workerBaseURI = baseURI + + const sendCmd = (params, transfer)=>{ + if(params.worker === 'render') + sendToRender(params, transfer) + else if(params.worker === 'script') + scriptWorker.postMessage(params, transfer) + else{ + // parameter definitions will arrive from scriptWorker + callback(params, transfer) + } + } + + const updateSize = function({width,height}){ + sendCmd({ action:'resize', worker:'render', width: canvas.offsetWidth, height: canvas.offsetHeight}) + } + + + renderInWorker = !!(canvas && renderInWorker && canvas.transferControlToOffscreen) + const makeRenderWorkerHere = (scope === 'main' && canvas && !renderInWorker) || (scope === 'worker' && render) + // worker is in current thread + if(makeRenderWorkerHere){ + console.log('render in scope: '+scope); + renderWorker = makeRenderWorker({callback:sendCmd}) + sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer) + } + + if(scope === 'main'){ +// let extraScript = renderInWorker ? `,'https://unpkg.com/@jscad/regl-renderer'`:'' + let script =`let baseURI = '${baseURI}' +importScripts(new URL('${scriptUrl}',baseURI)) +let worker = jscadWorker({ + baseURI: baseURI, + convertToSolids: ${convertToSolids}, + scope:'worker', + callback:(params)=>self.postMessage(params), + render:${renderInWorker} +}) +self.addEventListener('message', (e)=>worker.postMessage(e.data)) +` + let blob = new Blob([script],{type: 'text/javascript'}) + scriptWorker = new Worker(window.URL.createObjectURL(blob)) + scriptWorker.addEventListener('message',(e)=>sendCmd(e.data)) + scriptWorker.postMessage({action:'init', baseURI, alias}) + if(renderInWorker) renderWorker = scriptWorker + + if(canvas){ + initCanvas(canvas, sendCmd) + window.addEventListener('resize',updateSize) + } + }else{ + scriptWorker = makeScriptWorker({callback:sendCmd, convertToSolids}) + callback({action:'workerInit',worker:'main'}) + } + + if(canvas){ + // redirect 'render' messages to renderWorker + sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer) + let width = canvas.width = canvas.clientWidth + let height = canvas.height = canvas.clientHeight + if(scope == 'main'){ + const offscreen = renderInWorker ? canvas.transferControlToOffscreen() : canvas + renderWorker.postMessage({action:'init', worker:'render', canvas:offscreen, width, height}, [offscreen]) + } + } + + return { + updateSize, + updateParams:({params={}})=>sendCmd({ action:'updateParams', worker:'script', params}), + runScript: ({script,url=''})=>sendCmd({ action:'runScript', worker:'script', script, url}), + postMessage: sendCmd, + } +} + + +// multi purpose module +}); diff --git a/app/web/src/helpers/cadPackages/CSGToBuffers.js b/app/web/src/helpers/cadPackages/CSGToBuffers.js new file mode 100644 index 0000000..c9b5bbb --- /dev/null +++ b/app/web/src/helpers/cadPackages/CSGToBuffers.js @@ -0,0 +1,106 @@ +const setPoints = (points, p, i)=>{ + points[i++] = p[0] + points[i++] = p[1] + points[i++] = p[2] || 0 +} + +function CSG2Vertices(csg){ + let idx = 0 + + let vLen = 0, iLen = 0 + for (let poly of csg.polygons){ + let len = poly.vertices.length + vLen += len *3 + iLen += 3 * (len-2) + } + const vertices = new Float32Array(vLen) + const indices = vLen > 65535 ? new Uint32Array(iLen) : new Uint16Array(iLen) + + let vertOffset = 0 + let indOffset = 0 + let posOffset = 0 + let first = 0 + for (let poly of csg.polygons){ + let arr = poly.vertices + let len = arr.length + first = posOffset + vertices.set(arr[0], vertOffset) + vertOffset +=3 + vertices.set(arr[1], vertOffset) + vertOffset +=3 + posOffset +=2 + for(let i=2; isetPoints(vertices, p, idx * 3 )) + + if(csg.isClosed){ + setPoints(vertices, csg.points[0], vertices.length - 3 ) + } + return {vertices, type:'line'} +} + +function CSG2LineSegmentsVertices(csg){ + let vLen = csg.sides.length * 6 + + var vertices = new Float32Array(vLen) + csg.sides.forEach((side,idx)=>{ + let i = idx * 6 + setPoints(vertices, side[0], i) + setPoints(vertices, side[1], i+3) + }) + return {vertices, type:'lines'} + +} + +function CSGCached(func, data, cacheKey, transferable){ + cacheKey = cacheKey || data + + let geo = CSGToBuffers.cache.get(cacheKey) + if(geo) return geo + + geo = func(data) + + // fill transferable array for postMessage optimization + if(transferable){ + const {vertices, indices} = geo + transferable.push(vertices) + if(indices) transferable.push(indices) + } + + CSGToBuffers.cache.set(cacheKey, geo) + return geo +} + +function CSGToBuffers(csg, transferable){ + let obj + + if(csg.polygons) obj = CSGCached(CSG2Vertices,csg,csg.polygons, transferable) + if(csg.sides && !csg.points) obj = CSGCached(CSG2LineSegmentsVertices,csg,csg.sides, transferable) + if(csg.points) obj = CSGCached(CSG2LineVertices,csg,csg.points, transferable) + + return obj +} +CSGToBuffers.clearCache = ()=>{CSGToBuffers.cache = new WeakMap()} +CSGToBuffers.clearCache() + +export {CSGToBuffers} \ No newline at end of file diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index a31eeeb..ebe34a9 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -1,11 +1,107 @@ -import { RenderArgs, DefaultKernelExport, createUnhealthyResponse } from './common' +import { result } from 'lodash' +import { RenderArgs, DefaultKernelExport, createUnhealthyResponse, createHealthyResponse } from './common' +import { MeshPhongMaterial, LineBasicMaterial, BufferGeometry , BufferAttribute, Line, LineSegments, Color, Mesh, Group} from 'three/build/three.module' + + +const materials = { + mesh: { + def: new MeshPhongMaterial( { color: 0x0084d1, flatShading: true } ), + material: MeshPhongMaterial, + }, + line: { + def: new LineBasicMaterial( { color: 0x0000ff } ), + material: LineBasicMaterial, + }, + lines:null +} +materials.lines = materials.line + +function CSG2Object3D(obj){ + const {vertices, indices, color, transforms} = obj + + let materialDef = materials[obj.type] + if(!materialDef){ + console.error('Can not hangle object type: '+obj.type, obj) + return null + } + + let material = materialDef.def + if(color){ + let c = color + material = new materialDef.material({ color: new Color(c[0],c[1],c[2]), flatShading: true, opacity: c[3] === void 0 ? 1:c[3], transparent: c[3] != 1 && c[3] !== void 0}) + } + + var geo = new BufferGeometry() + if(transforms) geo.applyMatrix4({elements:transforms}) + geo.setAttribute('position', new BufferAttribute(vertices,3)) + + switch(obj.type){ + case 'mesh': geo.setIndex(new BufferAttribute(indices,1)); return new Mesh(geo, material) + case 'line': return new Line(geo, material) + case 'lines': return new LineSegments(geo, material) + } +} + +let scriptWorker +const scriptUrl = '/demo-worker.js' +let resolveReference = null +let response = null + +const callResolve = ()=>{ + if(resolveReference) resolveReference() + resolveReference +} export const render: DefaultKernelExport['render'] = async ({ code, settings, }: RenderArgs) => { - // do your magic - return createUnhealthyResponse( new Date(), 'JSCAD controller not implemented yet') + + if(!scriptWorker){ + const baseURI = document.baseURI.toString() + const script =`let baseURI = '${baseURI}' +importScripts(new URL('${scriptUrl}',baseURI)) +let worker = jscadWorker({ + baseURI: baseURI, + scope:'worker', + convertToSolids: 'buffers', + callback:(params)=>self.postMessage(params), +}) +self.addEventListener('message', (e)=>worker.postMessage(e.data)) +` + let blob = new Blob([script],{type: 'text/javascript'}) + scriptWorker = new Worker(window.URL.createObjectURL(blob)) + scriptWorker.addEventListener('message',(e)=>{ + console.log('message from worker', e.data) + let data = e.data + if(data.action == 'entities'){ + let group = new Group() + data.entities.map(CSG2Object3D).filter(o=>o).forEach(o=>group.add(o)) + response = createHealthyResponse( { + type: 'geometry', + data: group, + consoleMessage: data.scriptStats, + date: new Date(), + }) + callResolve() + } + }) + + callResolve() + response = null + scriptWorker.postMessage({action:'init', baseURI, alias:[]}) + } + scriptWorker.postMessage({action:'runScript', worker:'script', script:code, url:'jscad_script' }) + + let waitResult = new Promise(resolve=>{ + resolveReference = resolve + }) + + await waitResult + resolveReference = null + console.log('response', response) + if(!response) + return response } const jsCadController: DefaultKernelExport = { diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index c38d483..0acd810 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -43,7 +43,31 @@ result = (cq.Workplane().circle(diam).extrude(20.0) show_object(result) `, jscad: ` -// TODO implement example JSCAD code. +const { booleans, colors, primitives } = require('@jscad/modeling') // modeling comes from the included MODELING library + +const { intersect, subtract } = booleans +const { colorize } = colors +const { cube, cuboid, line, sphere, star } = primitives + +const main = ({scale=1}) => { + const logo = [ + colorize([1.0, 0.4, 1.0], subtract( + cube({ size: 300 }), + sphere({ radius: 200 }) + )), + colorize([1.0, 1.0, 0], intersect( + sphere({ radius: 130 }), + cube({ size: 210 }) + )) + ] + + const transpCube = colorize([1, 0, 0, 0.75], cuboid({ size: [100 * scale, 100, 210 + (200 * scale)] })) + const star2D = star({ vertices: 8, innerRadius: 150, outerRadius: 200 }) + const line2D = colorize([1.0, 0, 0], line([[220, 220], [-220, 220], [-220, -220], [220, -220], [220, 220]])) + + return [transpCube, star2D, line2D, ...logo] +} +module.exports = {main} ` } From 438a9135e4ceb30ec0d5ad24e22d92b3160c8991 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Mon, 26 Jul 2021 22:57:22 +0200 Subject: [PATCH 02/26] unhealthy on err --- app/web/public/demo-worker.js | 16 +++++++++++++-- .../helpers/cadPackages/jsCadController.ts | 20 +++++++++++-------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/web/public/demo-worker.js b/app/web/public/demo-worker.js index 4833ca6..8900fa1 100644 --- a/app/web/public/demo-worker.js +++ b/app/web/public/demo-worker.js @@ -246,7 +246,13 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ function runMain(params={}){ console.log('runMain'); let time = Date.now() - let solids = main(params) + let solids + try{ + solids = main(params) + }catch(e){ + callback({action:'entities', worker:'render', error:e.message, stack:e.stack.toString()}, transfer) + return + } let solidsTime = Date.now() - time scriptStats = `generate solids ${solidsTime}ms` @@ -271,7 +277,13 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ if(!initialized){ onInit = ()=>handlers.runScript({script,url, params}) } - let script_module = requireModule(url,script) + let script_module + try{ + script_module = requireModule(url,script) + }catch(e){ + callback({action:'entities', worker:'render', error:e.message, stack:e.stack.toString()}) + return + } main = script_module.exports.main let gp = script_module.exports.getParameterDefinitions if(gp){ diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index ebe34a9..c06901d 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -75,14 +75,18 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) console.log('message from worker', e.data) let data = e.data if(data.action == 'entities'){ - let group = new Group() - data.entities.map(CSG2Object3D).filter(o=>o).forEach(o=>group.add(o)) - response = createHealthyResponse( { - type: 'geometry', - data: group, - consoleMessage: data.scriptStats, - date: new Date(), - }) + if(data.error){ + response = createUnhealthyResponse( new Date(),data.error ) + }else{ + let group = new Group() + data.entities.map(CSG2Object3D).filter(o=>o).forEach(o=>group.add(o)) + response = createHealthyResponse( { + type: 'geometry', + data: group, + consoleMessage: data.scriptStats, + date: new Date(), + }) + } callResolve() } }) From 1479832b5184bc66fbd75ed4f6d7268aa8c45fe1 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Mon, 26 Jul 2021 23:01:51 +0200 Subject: [PATCH 03/26] stupid typo --- app/web/src/helpers/cadPackages/jsCadController.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index c06901d..0394858 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -104,7 +104,6 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) await waitResult resolveReference = null console.log('response', response) - if(!response) return response } From 3b1bb23563fb64c3685553592797946bfb9566a0 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Tue, 27 Jul 2021 07:48:56 +1000 Subject: [PATCH 04/26] getting some geometry into the 3d view --- .../src/helpers/cadPackages/jsCadController.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 0394858..79141ee 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -1,4 +1,3 @@ -import { result } from 'lodash' import { RenderArgs, DefaultKernelExport, createUnhealthyResponse, createHealthyResponse } from './common' import { MeshPhongMaterial, LineBasicMaterial, BufferGeometry , BufferAttribute, Line, LineSegments, Color, Mesh, Group} from 'three/build/three.module' @@ -63,9 +62,9 @@ export const render: DefaultKernelExport['render'] = async ({ importScripts(new URL('${scriptUrl}',baseURI)) let worker = jscadWorker({ baseURI: baseURI, - scope:'worker', + scope:'worker', convertToSolids: 'buffers', - callback:(params)=>self.postMessage(params), + callback:(params)=>self.postMessage(params), }) self.addEventListener('message', (e)=>worker.postMessage(e.data)) ` @@ -82,21 +81,21 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) data.entities.map(CSG2Object3D).filter(o=>o).forEach(o=>group.add(o)) response = createHealthyResponse( { type: 'geometry', - data: group, + data: group?.children[4]?.geometry, consoleMessage: data.scriptStats, date: new Date(), }) } - callResolve() + callResolve() } }) callResolve() response = null - scriptWorker.postMessage({action:'init', baseURI, alias:[]}) + scriptWorker.postMessage({action:'init', baseURI, alias:[]}) } - scriptWorker.postMessage({action:'runScript', worker:'script', script:code, url:'jscad_script' }) - + scriptWorker.postMessage({action:'runScript', worker:'script', script:code, url:'jscad_script' }) + let waitResult = new Promise(resolve=>{ resolveReference = resolve }) From 0b769a65242e885b4d35e0a7729e11207deafb2a Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Tue, 27 Jul 2021 10:36:02 +0200 Subject: [PATCH 05/26] something works --- app/web/public/demo-worker.js | 7 ++++++- app/web/src/components/IdeViewer/IdeViewer.tsx | 3 +++ app/web/src/helpers/cadPackages/jsCadController.ts | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/web/public/demo-worker.js b/app/web/public/demo-worker.js index 8900fa1..376ab16 100644 --- a/app/web/public/demo-worker.js +++ b/app/web/public/demo-worker.js @@ -259,7 +259,12 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ let transfer = [] if(convertToSolids === 'buffers'){ CSGToBuffers.clearCache() - entities = solids.map((csg)=>CSGToBuffers(csg, transfer)) + entities = solids.map((csg)=>{ + let obj = CSGToBuffers(csg, transfer) + obj.color = csg.color + obj.transforms = csg.transforms + return obj + }) }else if(convertToSolids === 'regl'){ const { entitiesFromSolids } = require('@jscad/regl-renderer') time = Date.now() diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 85675b6..ee22ef4 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -21,6 +21,9 @@ function Asset({ geometry: incomingGeo }) { } }, [incomingGeo]) if (!incomingGeo) return null + + if (incomingGeo.children) return + return ( diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 79141ee..08e481e 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -81,7 +81,7 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) data.entities.map(CSG2Object3D).filter(o=>o).forEach(o=>group.add(o)) response = createHealthyResponse( { type: 'geometry', - data: group?.children[4]?.geometry, + data: group, consoleMessage: data.scriptStats, date: new Date(), }) From 6e88e7030d272c803121f9fa69943c0ff0e853d2 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Tue, 27 Jul 2021 10:47:29 +0200 Subject: [PATCH 06/26] Update jsCadController.ts --- app/web/src/helpers/cadPackages/jsCadController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 08e481e..bb8a818 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -5,11 +5,11 @@ import { MeshPhongMaterial, LineBasicMaterial, BufferGeometry , BufferAttribute, const materials = { mesh: { def: new MeshPhongMaterial( { color: 0x0084d1, flatShading: true } ), - material: MeshPhongMaterial, + material: (params)=>new MeshPhongMaterial(params), }, line: { def: new LineBasicMaterial( { color: 0x0000ff } ), - material: LineBasicMaterial, + material: ({color,opacity,transparent})=>new LineBasicMaterial({color,opacity,transparent}), }, lines:null } From 8d0f2fca51c0e9ce6edbcfd12209a94364f0270c Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Tue, 27 Jul 2021 12:37:29 +0200 Subject: [PATCH 07/26] light tweaks --- app/web/src/components/IdeViewer/IdeViewer.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index ee22ef4..cf71f89 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -212,8 +212,8 @@ const IdeViewer = ({ Loading }) => { }) }} /> - - + + {state.objectData?.type === 'png' && ( From 2a3fb0fd8472b59d84ace8068adb384add81f062 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Wed, 28 Jul 2021 14:27:50 +0200 Subject: [PATCH 08/26] fix for react-fiber not properly cleaning the scene --- app/web/src/components/IdeViewer/IdeViewer.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index cf71f89..fcd3efd 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -10,9 +10,12 @@ import { TextureLoader } from 'three/src/loaders/TextureLoader' const loader = new TextureLoader() const colorMap = loader.load(texture) +let lastGroup + extend({ OrbitControls }) function Asset({ geometry: incomingGeo }) { + const state = useThree() const mesh = useRef() const ref = useRef({}) useLayoutEffect(() => { @@ -21,7 +24,20 @@ function Asset({ geometry: incomingGeo }) { } }, [incomingGeo]) if (!incomingGeo) return null - + + let groupData = incomingGeo.children ? incomingGeo : null + if(lastGroup && lastGroup != groupData){ + state.scene.remove(lastGroup) + lastGroup.children.forEach(c=>c?.geometry?.dispose()) + // returning does not add the new group to the scene + // there is probably some useRef magic that would make this work, but I don't have time to reseach it + /// FIXME - do this properly with useRef or other react magic + if(groupData) state.scene.add(groupData) + } + lastGroup = groupData + + if(groupData) return + if (incomingGeo.children) return return ( From 73cbb9dbb30881d3881dc25ca550d8f12cf3e066 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Wed, 28 Jul 2021 15:23:52 +0200 Subject: [PATCH 09/26] stl export for jscad --- app/web/src/components/EditorMenu/helpers.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/web/src/components/EditorMenu/helpers.ts b/app/web/src/components/EditorMenu/helpers.ts index ff050c6..a0d97eb 100644 --- a/app/web/src/components/EditorMenu/helpers.ts +++ b/app/web/src/components/EditorMenu/helpers.ts @@ -35,8 +35,7 @@ export const makeStlDownloadHandler = ideType, }: makeStlDownloadHandlerArgs) => () => { - const makeStlBlobFromGeo = flow( - (geo) => new Mesh(geo, new MeshBasicMaterial()), + const makeStlBlobFromMesh = flow( (mesh) => new Scene().add(mesh), (scene) => new STLExporter().parse(scene), (stl) => @@ -44,8 +43,11 @@ export const makeStlDownloadHandler = type: 'text/plain', }) ) - const saveFile = (geometry) => { - const blob = makeStlBlobFromGeo(geometry) + const makeStlBlobFromGeo = flow( + (geo) => new Mesh(geo, new MeshBasicMaterial()), + (mesh) => makeStlBlobFromMesh(mesh) + ) + const saveFile = (blob) => { fileSave(blob, { fileName, extensions: ['.stl'], @@ -56,7 +58,9 @@ export const makeStlDownloadHandler = type === 'geometry' && (quality === 'high' || ideType === 'openscad') ) { - saveFile(geometry) + saveFile(makeStlBlobFromGeo(geometry)) + } else if(ideType == 'jscad') { + saveFile(makeStlBlobFromMesh(geometry)) } else { thunkDispatch((dispatch, getState) => { const state = getState() From e4bf8f5e81799608fe59ce2788a21bfe14a99216 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Fri, 30 Jul 2021 21:04:28 +1000 Subject: [PATCH 10/26] Add social preview page --- app/web/src/Routes.js | 1 + app/web/src/components/Gravatar/Gravatar.tsx | 5 +- .../src/components/IdeWrapper/useSaveCode.ts | 2 +- .../SocialCardCell/SocialCardCell.tsx | 144 ++++++++++++++++++ app/web/src/components/Svg/Svg.tsx | 49 ++++++ .../pages/SocialCardPage/SocialCardPage.tsx | 13 ++ app/web/tailwind.config.js | 2 + 7 files changed, 213 insertions(+), 3 deletions(-) create mode 100644 app/web/src/components/SocialCardCell/SocialCardCell.tsx create mode 100644 app/web/src/pages/SocialCardPage/SocialCardPage.tsx diff --git a/app/web/src/Routes.js b/app/web/src/Routes.js index 665ad9d..4279d72 100644 --- a/app/web/src/Routes.js +++ b/app/web/src/Routes.js @@ -55,6 +55,7 @@ const Routes = () => { + diff --git a/app/web/src/components/Gravatar/Gravatar.tsx b/app/web/src/components/Gravatar/Gravatar.tsx index 58ea606..08603f5 100644 --- a/app/web/src/components/Gravatar/Gravatar.tsx +++ b/app/web/src/components/Gravatar/Gravatar.tsx @@ -4,9 +4,10 @@ import { Image as CloudinaryImage } from 'cloudinary-react' interface Props { image: string className?: string + size?: number } -const Gravatar = ({ image, className = '' }: Props) => { +const Gravatar = ({ image, size = 40, className = '' }: Props) => { return (
{
diff --git a/app/web/src/components/IdeWrapper/useSaveCode.ts b/app/web/src/components/IdeWrapper/useSaveCode.ts index 8a26161..69dcd71 100644 --- a/app/web/src/components/IdeWrapper/useSaveCode.ts +++ b/app/web/src/components/IdeWrapper/useSaveCode.ts @@ -19,7 +19,7 @@ export const useSaveCode = () => { setNowError(!!error) } if (!currentUser || project?.user?.id !== currentUser?.sub) { - return () => console.log('not your project') + return () => {} } return (input: Prisma.ProjectUpdateInput) => { updateProject({ variables: { id: project.id, input } }) diff --git a/app/web/src/components/SocialCardCell/SocialCardCell.tsx b/app/web/src/components/SocialCardCell/SocialCardCell.tsx new file mode 100644 index 0000000..8182221 --- /dev/null +++ b/app/web/src/components/SocialCardCell/SocialCardCell.tsx @@ -0,0 +1,144 @@ +import type { FindSocialCardQuery } from 'types/graphql' +import type { CellSuccessProps, CellFailureProps } from '@redwoodjs/web' +import Svg from 'src/components/Svg/Svg' +import { Image as CloudinaryImage } from 'cloudinary-react' +import Gravatar from 'src/components/Gravatar/Gravatar' +import CadPackage from 'src/components/CadPackage/CadPackage' + +export const QUERY = gql` + query FindSocialCardQuery($userName: String!, $projectTitle: String) { + userProject: userName(userName: $userName) { + userName + image + Project(projectTitle: $projectTitle) { + id + title + description + mainImage + createdAt + updatedAt + userId + cadPackage + Reaction { + emote + } + } + } + } +` + +export const Loading = () =>
Loading...
+ +export const Empty = () =>
Empty
+ +export const Failure = ({ error }: CellFailureProps) => ( +
Error: {error.message}
+) + +export const Success = ({ + userProject, +}: CellSuccessProps) => { + const image = userProject?.Project?.mainImage + const gravatar = userProject?.image + return ( +
+
+
+
+ {/* */} +
+ +
+
+
+ {gravatar && ( + + )} +
+ {userProject?.userName} +
+
+ +
+ +

+ {userProject?.Project?.title.replace(/-/g, ' ')} +

+ +

+ {(userProject?.Project?.description || '').slice(0, 150)} +

+
+
+
+
+ +
+
+
+
+
+ {[ + { + svg: 'reactions', + title: 'Reactions', + count: userProject?.Project?.Reaction?.length, + }, + { + svg: 'fork-new', + title: 'Forks', + count: 0, + }, + ].map(({ svg, title, count }, index) => ( +
+ +
+
{count}
+
{title}
+
+
+ ))} +
+
+ +
+ {/* Because of how specific these styles are to this heading/logo and it doesn't need to be replicated else where as well as it's very precise with the placement of "pre-alpha" I think it's appropriate. */} +

+ CadHub +

+
+ pre-alpha +
+
+
+
+
+
+ ) +} diff --git a/app/web/src/components/Svg/Svg.tsx b/app/web/src/components/Svg/Svg.tsx index 2313dff..f21612d 100644 --- a/app/web/src/components/Svg/Svg.tsx +++ b/app/web/src/components/Svg/Svg.tsx @@ -13,6 +13,7 @@ type SvgNames = | 'flag' | 'floppy-disk' | 'fork' + | 'fork-new' | 'gear' | 'lightbulb' | 'logout' @@ -22,6 +23,7 @@ type SvgNames = | 'photograph' | 'plus' | 'plus-circle' + | 'reactions' | 'refresh' | 'save' | 'share' @@ -294,6 +296,39 @@ const Svg = ({ /> ), + 'fork-new': ( + + + + + + + ), gear: ( ), + reactions: ( + + + + + ), refresh: ( { + return +} + +export default SocialCardPage diff --git a/app/web/tailwind.config.js b/app/web/tailwind.config.js index e492a68..e1dca04 100644 --- a/app/web/tailwind.config.js +++ b/app/web/tailwind.config.js @@ -22,6 +22,7 @@ module.exports = { 700: '#2A3038', 600: '#3B3E4B', 500: '#9F9FB4', + 400: '#A4A4B0', 300: '#CFCFD8', }, 'ch-purple': { @@ -31,6 +32,7 @@ module.exports = { }, 'ch-blue': { 600: '#79B2F8', + 500: '5098F1', 300: '#08466F' }, 'ch-pink': { From cbaa79b697a06c658a392cbad02392b73c5f41ec Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 31 Jul 2021 15:25:30 +1000 Subject: [PATCH 11/26] add netlify builder to capture social images plus also added an invalidator that should invalidate the image each month --- app/api/package.json | 6 +- app/api/src/functions/og-image-generator.ts | 63 +++++++ .../src/components/Seo/{Seo.js => Seo.tsx} | 3 +- .../SocialCardCell/SocialCardCell.tsx | 4 +- .../src/pages/NotFoundPage/NotFoundPage.js | 1 + app/web/src/pages/ProjectPage/ProjectPage.tsx | 4 +- app/yarn.lock | 176 ++++++++++++++++-- 7 files changed, 238 insertions(+), 19 deletions(-) create mode 100644 app/api/src/functions/og-image-generator.ts rename app/web/src/components/Seo/{Seo.js => Seo.tsx} (71%) diff --git a/app/api/package.json b/app/api/package.json index b56a4c1..a57d377 100644 --- a/app/api/package.json +++ b/app/api/package.json @@ -3,11 +3,15 @@ "version": "0.0.0", "private": true, "dependencies": { + "@netlify/functions": "^0.7.2", "@redwoodjs/api": "^0.34.1", "@sentry/node": "^6.5.1", + "chrome-aws-lambda": "^10.1.0", "cloudinary": "^1.23.0", "human-id": "^2.0.1", - "nodemailer": "^6.6.2" + "nodemailer": "^6.6.2", + "puppeteer": "^10.1.0", + "puppeteer-core": "^10.1.0" }, "devDependencies": { "@types/nodemailer": "^6.4.2" diff --git a/app/api/src/functions/og-image-generator.ts b/app/api/src/functions/og-image-generator.ts new file mode 100644 index 0000000..d82b84b --- /dev/null +++ b/app/api/src/functions/og-image-generator.ts @@ -0,0 +1,63 @@ +import { builder } from '@netlify/functions' +import type { HandlerResponse } from '@netlify/functions' +import chromium from 'chrome-aws-lambda' + +const captureWidth = 1200 +const captureHeight = 630 +const clipY = 0 + +async function unwrappedHandler (event, context): Promise { + let path = event.path + .replace(/.+\/og-image-generator/, '') + .replace(/\/og-image-.+\.jpg/, '') + + const url = `${process.env.URL}/u${path}/social-card` + + const browser = await chromium.puppeteer.launch({ + executablePath: process.env.URL?.includes('localhost') + ? null + : await chromium.executablePath, + args: ['--no-sandbox','--disable-web-security','--disable-gpu', '--hide-scrollbars', '--disable-setuid-sandbox'], + // args: chromium.args, + defaultViewport: { + width: captureWidth, + height: captureHeight + clipY + }, + headless: chromium.headless + }) + const page = await browser.newPage() + + await page.goto(url, {"waitUntil" : "networkidle0"}); + + const screenshot = await page.screenshot({ + type: 'jpeg', + // netlify functions can only return strings, so base64 it is + encoding: 'base64', + quality: 70, + clip: { + x: 0, + y: clipY, + width: captureWidth, + height: captureHeight + } + }) + + await browser.close() + + if (typeof screenshot !== 'string') { + return { + statusCode: 400, + } + } + + return { + statusCode: 200, + headers: { + 'Content-Type': 'image/jpg' + }, + body: screenshot, + isBase64Encoded: true + } +} + +export const handler = builder(unwrappedHandler) diff --git a/app/web/src/components/Seo/Seo.js b/app/web/src/components/Seo/Seo.tsx similarity index 71% rename from app/web/src/components/Seo/Seo.js rename to app/web/src/components/Seo/Seo.tsx index 69d97f0..1697b8d 100644 --- a/app/web/src/components/Seo/Seo.js +++ b/app/web/src/components/Seo/Seo.tsx @@ -1,6 +1,6 @@ import { Helmet } from 'react-helmet' -const Seo = ({ title, description, lang }) => { +const Seo = ({ title, description, lang, socialImageUrl}: { title: string; description: string; lang: string; socialImageUrl?: string}) => { return ( <> { + Cadhub - {title} diff --git a/app/web/src/components/SocialCardCell/SocialCardCell.tsx b/app/web/src/components/SocialCardCell/SocialCardCell.tsx index 8182221..01ee464 100644 --- a/app/web/src/components/SocialCardCell/SocialCardCell.tsx +++ b/app/web/src/components/SocialCardCell/SocialCardCell.tsx @@ -41,7 +41,7 @@ export const Success = ({ const image = userProject?.Project?.mainImage const gravatar = userProject?.image return ( -
+
-
+
(

404 Page Not Found +
{location.href} 🤷

diff --git a/app/web/src/pages/ProjectPage/ProjectPage.tsx b/app/web/src/pages/ProjectPage/ProjectPage.tsx index 7e401ca..24577be 100644 --- a/app/web/src/pages/ProjectPage/ProjectPage.tsx +++ b/app/web/src/pages/ProjectPage/ProjectPage.tsx @@ -9,9 +9,11 @@ import { Toaster } from '@redwoodjs/web/toast' const ProjectPage = ({ userName, projectTitle }) => { const { currentUser } = useAuth() const [state, thunkDispatch] = useIdeState() + const cacheInvalidator = new Date().toISOString().split('-').slice(0, 2).join('-') + const socialImageUrl = `/.netlify/functions/og-image-generator/${userName}/${projectTitle}/og-image-${cacheInvalidator}.jpg` return ( <> - + Date: Sat, 31 Jul 2021 17:04:20 +1000 Subject: [PATCH 12/26] attempt to got functions to deploy --- app/api/src/functions/og-image-generator.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/api/src/functions/og-image-generator.ts b/app/api/src/functions/og-image-generator.ts index d82b84b..4a50e47 100644 --- a/app/api/src/functions/og-image-generator.ts +++ b/app/api/src/functions/og-image-generator.ts @@ -1,6 +1,6 @@ import { builder } from '@netlify/functions' import type { HandlerResponse } from '@netlify/functions' -import chromium from 'chrome-aws-lambda' +const { headless, executablePath, puppeteer} = require('chrome-aws-lambda') const captureWidth = 1200 const captureHeight = 630 @@ -13,17 +13,17 @@ async function unwrappedHandler (event, context): Promise { const url = `${process.env.URL}/u${path}/social-card` - const browser = await chromium.puppeteer.launch({ + const browser = await puppeteer.launch({ executablePath: process.env.URL?.includes('localhost') ? null - : await chromium.executablePath, + : await executablePath, args: ['--no-sandbox','--disable-web-security','--disable-gpu', '--hide-scrollbars', '--disable-setuid-sandbox'], // args: chromium.args, defaultViewport: { width: captureWidth, height: captureHeight + clipY }, - headless: chromium.headless + headless: headless }) const page = await browser.newPage() From 6d68b939bebd3e875a14d8f7298ac22246c6544b Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sat, 31 Jul 2021 17:26:10 +1000 Subject: [PATCH 13/26] try moving things into dev dependencies --- app/api/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/package.json b/app/api/package.json index a57d377..354a796 100644 --- a/app/api/package.json +++ b/app/api/package.json @@ -3,17 +3,17 @@ "version": "0.0.0", "private": true, "dependencies": { - "@netlify/functions": "^0.7.2", "@redwoodjs/api": "^0.34.1", "@sentry/node": "^6.5.1", "chrome-aws-lambda": "^10.1.0", "cloudinary": "^1.23.0", "human-id": "^2.0.1", "nodemailer": "^6.6.2", - "puppeteer": "^10.1.0", "puppeteer-core": "^10.1.0" }, "devDependencies": { + "@netlify/functions": "^0.7.2", + "puppeteer": "^10.1.0", "@types/nodemailer": "^6.4.2" } } From 22f3fb6e3e0f895e1051cc758ddc424b674898d7 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 04:45:43 +1000 Subject: [PATCH 14/26] Remove og image types --- app/api/src/functions/og-image-generator.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/api/src/functions/og-image-generator.ts b/app/api/src/functions/og-image-generator.ts index 4a50e47..791a27c 100644 --- a/app/api/src/functions/og-image-generator.ts +++ b/app/api/src/functions/og-image-generator.ts @@ -1,12 +1,11 @@ import { builder } from '@netlify/functions' -import type { HandlerResponse } from '@netlify/functions' const { headless, executablePath, puppeteer} = require('chrome-aws-lambda') const captureWidth = 1200 const captureHeight = 630 const clipY = 0 -async function unwrappedHandler (event, context): Promise { +async function unwrappedHandler (event, context) { let path = event.path .replace(/.+\/og-image-generator/, '') .replace(/\/og-image-.+\.jpg/, '') From 8162a182d7b99d3596e7188a5df9ca68dc4896a2 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Sat, 31 Jul 2021 21:03:44 +0200 Subject: [PATCH 15/26] Update jsCadController.ts --- app/web/src/helpers/cadPackages/jsCadController.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index bb8a818..dd686f9 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -31,14 +31,16 @@ function CSG2Object3D(obj){ } var geo = new BufferGeometry() - if(transforms) geo.applyMatrix4({elements:transforms}) geo.setAttribute('position', new BufferAttribute(vertices,3)) + var mesh; switch(obj.type){ - case 'mesh': geo.setIndex(new BufferAttribute(indices,1)); return new Mesh(geo, material) - case 'line': return new Line(geo, material) - case 'lines': return new LineSegments(geo, material) + case 'mesh': geo.setIndex(new BufferAttribute(indices,1)); mesh = new THREE.Mesh(geo, material); break; + case 'line': mesh = new Line(geo, material); break; + case 'lines': mesh = new LineSegments(geo, material); break; } + if(transforms) mesh.applyMatrix4({elements:transforms}) + return mesh } let scriptWorker From caf944716b9e23ba254a73387d212d98f16c9bdf Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 09:42:15 +1000 Subject: [PATCH 16/26] Move og-image-gen out of functions folder --- app/api/src/{functions => services}/og-image-generator.ts | 3 +++ 1 file changed, 3 insertions(+) rename app/api/src/{functions => services}/og-image-generator.ts (85%) diff --git a/app/api/src/functions/og-image-generator.ts b/app/api/src/services/og-image-generator.ts similarity index 85% rename from app/api/src/functions/og-image-generator.ts rename to app/api/src/services/og-image-generator.ts index 791a27c..f5877c6 100644 --- a/app/api/src/functions/og-image-generator.ts +++ b/app/api/src/services/og-image-generator.ts @@ -1,3 +1,6 @@ +// TODO this should be in the functions folder. +// Got the proof of concept working locally, but even though chrome-aws-lambda is supposed to fit into a AWS lambda it did not for me +// in the mean time this is causing builds to fail so moved it out here. import { builder } from '@netlify/functions' const { headless, executablePath, puppeteer} = require('chrome-aws-lambda') From ad0e9c1d4dae97ba3227dc795b59c0bc34ea9f0e Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 09:44:10 +1000 Subject: [PATCH 17/26] format project --- app/api/src/services/og-image-generator.ts | 28 +++++++++++-------- app/web/src/components/Seo/Seo.tsx | 12 +++++++- .../SocialCardCell/SocialCardCell.tsx | 5 +++- app/web/src/pages/ProjectPage/ProjectPage.tsx | 13 +++++++-- 4 files changed, 43 insertions(+), 15 deletions(-) diff --git a/app/api/src/services/og-image-generator.ts b/app/api/src/services/og-image-generator.ts index f5877c6..93adbdd 100644 --- a/app/api/src/services/og-image-generator.ts +++ b/app/api/src/services/og-image-generator.ts @@ -2,14 +2,14 @@ // Got the proof of concept working locally, but even though chrome-aws-lambda is supposed to fit into a AWS lambda it did not for me // in the mean time this is causing builds to fail so moved it out here. import { builder } from '@netlify/functions' -const { headless, executablePath, puppeteer} = require('chrome-aws-lambda') +const { headless, executablePath, puppeteer } = require('chrome-aws-lambda') const captureWidth = 1200 const captureHeight = 630 const clipY = 0 -async function unwrappedHandler (event, context) { - let path = event.path +async function unwrappedHandler(event, context) { + const path = event.path .replace(/.+\/og-image-generator/, '') .replace(/\/og-image-.+\.jpg/, '') @@ -19,17 +19,23 @@ async function unwrappedHandler (event, context) { executablePath: process.env.URL?.includes('localhost') ? null : await executablePath, - args: ['--no-sandbox','--disable-web-security','--disable-gpu', '--hide-scrollbars', '--disable-setuid-sandbox'], + args: [ + '--no-sandbox', + '--disable-web-security', + '--disable-gpu', + '--hide-scrollbars', + '--disable-setuid-sandbox', + ], // args: chromium.args, defaultViewport: { width: captureWidth, - height: captureHeight + clipY + height: captureHeight + clipY, }, - headless: headless + headless: headless, }) const page = await browser.newPage() - await page.goto(url, {"waitUntil" : "networkidle0"}); + await page.goto(url, { waitUntil: 'networkidle0' }) const screenshot = await page.screenshot({ type: 'jpeg', @@ -40,8 +46,8 @@ async function unwrappedHandler (event, context) { x: 0, y: clipY, width: captureWidth, - height: captureHeight - } + height: captureHeight, + }, }) await browser.close() @@ -55,10 +61,10 @@ async function unwrappedHandler (event, context) { return { statusCode: 200, headers: { - 'Content-Type': 'image/jpg' + 'Content-Type': 'image/jpg', }, body: screenshot, - isBase64Encoded: true + isBase64Encoded: true, } } diff --git a/app/web/src/components/Seo/Seo.tsx b/app/web/src/components/Seo/Seo.tsx index 1697b8d..7c8adc5 100644 --- a/app/web/src/components/Seo/Seo.tsx +++ b/app/web/src/components/Seo/Seo.tsx @@ -1,6 +1,16 @@ import { Helmet } from 'react-helmet' -const Seo = ({ title, description, lang, socialImageUrl}: { title: string; description: string; lang: string; socialImageUrl?: string}) => { +const Seo = ({ + title, + description, + lang, + socialImageUrl, +}: { + title: string + description: string + lang: string + socialImageUrl?: string +}) => { return ( <> +
{ const { currentUser } = useAuth() const [state, thunkDispatch] = useIdeState() - const cacheInvalidator = new Date().toISOString().split('-').slice(0, 2).join('-') + const cacheInvalidator = new Date() + .toISOString() + .split('-') + .slice(0, 2) + .join('-') const socialImageUrl = `/.netlify/functions/og-image-generator/${userName}/${projectTitle}/og-image-${cacheInvalidator}.jpg` return ( <> - + Date: Sun, 1 Aug 2021 09:55:07 +1000 Subject: [PATCH 18/26] format project --- app/web/public/demo-worker.js | 59 +++--- app/web/src/components/EditorMenu/helpers.ts | 2 +- .../src/components/IdeEditor/IdeEditor.tsx | 2 +- .../src/components/IdeViewer/IdeViewer.tsx | 10 +- .../NavPlusButton/NavPlusButton.tsx | 1 - .../src/helpers/cadPackages/CSGToBuffers.js | 177 +++++++++--------- app/web/src/helpers/cadPackages/index.ts | 2 +- .../helpers/cadPackages/jsCadController.ts | 136 +++++++++----- app/web/src/helpers/hooks/useIdeState.ts | 6 +- 9 files changed, 215 insertions(+), 180 deletions(-) diff --git a/app/web/public/demo-worker.js b/app/web/public/demo-worker.js index 376ab16..ebbb97c 100644 --- a/app/web/public/demo-worker.js +++ b/app/web/public/demo-worker.js @@ -24,7 +24,7 @@ const setPoints = (points, p, i)=>{ points[i++] = p[0] points[i++] = p[1] - points[i++] = p[2] || 0 + points[i++] = p[2] || 0 } function CSG2Vertices(csg){ @@ -54,11 +54,11 @@ function CSG2Vertices(csg){ posOffset +=2 for(let i=2; isetPoints(vertices, p, idx * 3 )) - + if(csg.isClosed){ setPoints(vertices, csg.points[0], vertices.length - 3 ) } return {vertices, type:'line'} -} +} function CSG2LineSegmentsVertices(csg){ let vLen = csg.sides.length * 6 var vertices = new Float32Array(vLen) csg.sides.forEach((side,idx)=>{ - let i = idx * 6 + let i = idx * 6 setPoints(vertices, side[0], i) setPoints(vertices, side[1], i+3) }) @@ -104,14 +104,14 @@ function CSGCached(func, data, cacheKey, transferable){ geo = func(data) // fill transferable array for postMessage optimization - if(transferable){ + if(transferable){ const {vertices, indices} = geo transferable.push(vertices) if(indices) transferable.push(indices) } CSGToBuffers.cache.set(cacheKey, geo) - return geo + return geo } function CSGToBuffers(csg, transferable){ @@ -159,7 +159,7 @@ function requireModule(url, source){ try { const exports={}; if(!source) source = requireFile(url) - const module = { id: url, uri: url, exports:exports, source }; //according to node.js modules + const module = { id: url, uri: url, exports:exports, source }; //according to node.js modules // fix, add comment to show source on Chrome Dev Tools source="//@ sourceURL="+url+"\n" + source; //------ @@ -172,7 +172,7 @@ function requireModule(url, source){ } } -require.cache = {} +require.cache = {} require.alias = {} @@ -189,7 +189,7 @@ const initCanvas = (canvas, callback)=>{ const cmd = { worker: 'render', dx: lastX - ev.pageX, - dy: ev.pageY - lastY + dy: ev.pageY - lastY } const shiftKey = (ev.shiftKey === true) || (ev.touches && ev.touches.length > 2) @@ -244,7 +244,6 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ let workerBaseURI, onInit function runMain(params={}){ - console.log('runMain'); let time = Date.now() let solids try{ @@ -265,7 +264,7 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ obj.transforms = csg.transforms return obj }) - }else if(convertToSolids === 'regl'){ + }else if(convertToSolids === 'regl'){ const { entitiesFromSolids } = require('@jscad/regl-renderer') time = Date.now() entities = entitiesFromSolids({}, solids) @@ -281,12 +280,12 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ runScript: ({script,url, params={}})=>{ if(!initialized){ onInit = ()=>handlers.runScript({script,url, params}) - } + } let script_module try{ script_module = requireModule(url,script) }catch(e){ - callback({action:'entities', worker:'render', error:e.message, stack:e.stack.toString()}) + callback({action:'entities', worker:'render', error:e.message, stack:e.stack.toString()}) return } main = script_module.exports.main @@ -304,12 +303,12 @@ const makeScriptWorker = ({callback, convertToSolids})=>{ if(!baseURI && typeof document != 'undefined' && document.baseURI){ baseURI = document.baseURI } - + if(baseURI) workerBaseURI = baseURI.toString() alias.forEach(arr=>{ let [orig, ...aliases] = arr - aliases.forEach(a=>{ + aliases.forEach(a=>{ require.alias[a] = orig if(a.toLowerCase().substr(-3)!=='.js') require.alias[a+'.js'] = orig }) @@ -392,7 +391,7 @@ let perspectiveCamera glOptions: {gl} } if(type == 'webgl'){ - setupOptions.glOptions.optionalExtensions = ['oes_element_index_uint'] + setupOptions.glOptions.optionalExtensions = ['oes_element_index_uint'] } renderer = prepareRender(setupOptions) @@ -412,7 +411,7 @@ let perspectiveCamera axisOptions = { visuals: { drawCmd: 'drawAxis', - show: axis.show || axis.show === undefined + show: axis.show || axis.show === undefined }, size: axis.size || 100, } @@ -492,7 +491,7 @@ let perspectiveCamera } } - function resize({width,height}){ + function resize({width,height}){ state.canvas.width = width state.canvas.height = height perspectiveCamera.setProjection(state.camera, state.camera, { width, height }) @@ -504,7 +503,7 @@ let perspectiveCamera pan: ({dx,dy})=>{ panDelta[0] += dx panDelta[1] += dy - updateView() + updateView() }, rotate: ({dx,dy})=>{ rotateDelta[0] -= dx @@ -550,7 +549,7 @@ return (params)=>{ workerBaseURI = baseURI const sendCmd = (params, transfer)=>{ - if(params.worker === 'render') + if(params.worker === 'render') sendToRender(params, transfer) else if(params.worker === 'script') scriptWorker.postMessage(params, transfer) @@ -572,7 +571,7 @@ return (params)=>{ console.log('render in scope: '+scope); renderWorker = makeRenderWorker({callback:sendCmd}) sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer) - } + } if(scope === 'main'){ // let extraScript = renderInWorker ? `,'https://unpkg.com/@jscad/regl-renderer'`:'' @@ -581,8 +580,8 @@ importScripts(new URL('${scriptUrl}',baseURI)) let worker = jscadWorker({ baseURI: baseURI, convertToSolids: ${convertToSolids}, - scope:'worker', - callback:(params)=>self.postMessage(params), + scope:'worker', + callback:(params)=>self.postMessage(params), render:${renderInWorker} }) self.addEventListener('message', (e)=>worker.postMessage(e.data)) @@ -602,7 +601,7 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) callback({action:'workerInit',worker:'main'}) } - if(canvas){ + if(canvas){ // redirect 'render' messages to renderWorker sendToRender = (params, transfer)=>renderWorker.postMessage(params, transfer) let width = canvas.width = canvas.clientWidth @@ -613,7 +612,7 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) } } - return { + return { updateSize, updateParams:({params={}})=>sendCmd({ action:'updateParams', worker:'script', params}), runScript: ({script,url=''})=>sendCmd({ action:'runScript', worker:'script', script, url}), diff --git a/app/web/src/components/EditorMenu/helpers.ts b/app/web/src/components/EditorMenu/helpers.ts index a0d97eb..2393ac7 100644 --- a/app/web/src/components/EditorMenu/helpers.ts +++ b/app/web/src/components/EditorMenu/helpers.ts @@ -59,7 +59,7 @@ export const makeStlDownloadHandler = (quality === 'high' || ideType === 'openscad') ) { saveFile(makeStlBlobFromGeo(geometry)) - } else if(ideType == 'jscad') { + } else if (ideType == 'jscad') { saveFile(makeStlBlobFromMesh(geometry)) } else { thunkDispatch((dispatch, getState) => { diff --git a/app/web/src/components/IdeEditor/IdeEditor.tsx b/app/web/src/components/IdeEditor/IdeEditor.tsx index 67abf8d..2a514f5 100644 --- a/app/web/src/components/IdeEditor/IdeEditor.tsx +++ b/app/web/src/components/IdeEditor/IdeEditor.tsx @@ -14,7 +14,7 @@ const IdeEditor = ({ Loading }) => { const [theme, setTheme] = useState('vs-dark') const saveCode = useSaveCode() - const ideTypeToLanguageMap: {[key in CadPackageType]: string} = { + const ideTypeToLanguageMap: { [key in CadPackageType]: string } = { cadquery: 'python', openscad: 'cpp', jscad: 'javascript', diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index fcd3efd..15e0175 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -25,18 +25,18 @@ function Asset({ geometry: incomingGeo }) { }, [incomingGeo]) if (!incomingGeo) return null - let groupData = incomingGeo.children ? incomingGeo : null - if(lastGroup && lastGroup != groupData){ + const groupData = incomingGeo.children ? incomingGeo : null + if (lastGroup && lastGroup != groupData) { state.scene.remove(lastGroup) - lastGroup.children.forEach(c=>c?.geometry?.dispose()) + lastGroup.children.forEach((c) => c?.geometry?.dispose()) // returning does not add the new group to the scene // there is probably some useRef magic that would make this work, but I don't have time to reseach it /// FIXME - do this properly with useRef or other react magic - if(groupData) state.scene.add(groupData) + if (groupData) state.scene.add(groupData) } lastGroup = groupData - if(groupData) return + if (groupData) return if (incomingGeo.children) return diff --git a/app/web/src/components/NavPlusButton/NavPlusButton.tsx b/app/web/src/components/NavPlusButton/NavPlusButton.tsx index 467902c..d17e1d2 100644 --- a/app/web/src/components/NavPlusButton/NavPlusButton.tsx +++ b/app/web/src/components/NavPlusButton/NavPlusButton.tsx @@ -3,7 +3,6 @@ import Svg from 'src/components/Svg/Svg' import { Popover } from '@headlessui/react' import type { CadPackage } from 'src/helpers/hooks/useIdeState' - const menuOptions: { name: string sub: string diff --git a/app/web/src/helpers/cadPackages/CSGToBuffers.js b/app/web/src/helpers/cadPackages/CSGToBuffers.js index c9b5bbb..72ca689 100644 --- a/app/web/src/helpers/cadPackages/CSGToBuffers.js +++ b/app/web/src/helpers/cadPackages/CSGToBuffers.js @@ -1,106 +1,109 @@ -const setPoints = (points, p, i)=>{ - points[i++] = p[0] - points[i++] = p[1] - points[i++] = p[2] || 0 +const setPoints = (points, p, i) => { + points[i++] = p[0] + points[i++] = p[1] + points[i++] = p[2] || 0 } -function CSG2Vertices(csg){ - let idx = 0 +function CSG2Vertices(csg) { + let idx = 0 - let vLen = 0, iLen = 0 - for (let poly of csg.polygons){ - let len = poly.vertices.length - vLen += len *3 - iLen += 3 * (len-2) + let vLen = 0, + iLen = 0 + for (let poly of csg.polygons) { + let len = poly.vertices.length + vLen += len * 3 + iLen += 3 * (len - 2) + } + const vertices = new Float32Array(vLen) + const indices = vLen > 65535 ? new Uint32Array(iLen) : new Uint16Array(iLen) + + let vertOffset = 0 + let indOffset = 0 + let posOffset = 0 + let first = 0 + for (let poly of csg.polygons) { + let arr = poly.vertices + let len = arr.length + first = posOffset + vertices.set(arr[0], vertOffset) + vertOffset += 3 + vertices.set(arr[1], vertOffset) + vertOffset += 3 + posOffset += 2 + for (let i = 2; i < len; i++) { + vertices.set(arr[i], vertOffset) + + indices[indOffset++] = first + indices[indOffset++] = first + i - 1 + indices[indOffset++] = first + i + + vertOffset += 3 + posOffset += 1 } - const vertices = new Float32Array(vLen) - const indices = vLen > 65535 ? new Uint32Array(iLen) : new Uint16Array(iLen) - - let vertOffset = 0 - let indOffset = 0 - let posOffset = 0 - let first = 0 - for (let poly of csg.polygons){ - let arr = poly.vertices - let len = arr.length - first = posOffset - vertices.set(arr[0], vertOffset) - vertOffset +=3 - vertices.set(arr[1], vertOffset) - vertOffset +=3 - posOffset +=2 - for(let i=2; isetPoints(vertices, p, idx * 3 )) - - if(csg.isClosed){ - setPoints(vertices, csg.points[0], vertices.length - 3 ) - } - return {vertices, type:'line'} -} - -function CSG2LineSegmentsVertices(csg){ - let vLen = csg.sides.length * 6 - - var vertices = new Float32Array(vLen) - csg.sides.forEach((side,idx)=>{ - let i = idx * 6 - setPoints(vertices, side[0], i) - setPoints(vertices, side[1], i+3) - }) - return {vertices, type:'lines'} + csg.points.forEach((p, idx) => setPoints(vertices, p, idx * 3)) + if (csg.isClosed) { + setPoints(vertices, csg.points[0], vertices.length - 3) + } + return { vertices, type: 'line' } } -function CSGCached(func, data, cacheKey, transferable){ - cacheKey = cacheKey || data +function CSG2LineSegmentsVertices(csg) { + let vLen = csg.sides.length * 6 - let geo = CSGToBuffers.cache.get(cacheKey) - if(geo) return geo - - geo = func(data) - - // fill transferable array for postMessage optimization - if(transferable){ - const {vertices, indices} = geo - transferable.push(vertices) - if(indices) transferable.push(indices) - } - - CSGToBuffers.cache.set(cacheKey, geo) - return geo + var vertices = new Float32Array(vLen) + csg.sides.forEach((side, idx) => { + let i = idx * 6 + setPoints(vertices, side[0], i) + setPoints(vertices, side[1], i + 3) + }) + return { vertices, type: 'lines' } } -function CSGToBuffers(csg, transferable){ - let obj +function CSGCached(func, data, cacheKey, transferable) { + cacheKey = cacheKey || data - if(csg.polygons) obj = CSGCached(CSG2Vertices,csg,csg.polygons, transferable) - if(csg.sides && !csg.points) obj = CSGCached(CSG2LineSegmentsVertices,csg,csg.sides, transferable) - if(csg.points) obj = CSGCached(CSG2LineVertices,csg,csg.points, transferable) + let geo = CSGToBuffers.cache.get(cacheKey) + if (geo) return geo - return obj + geo = func(data) + + // fill transferable array for postMessage optimization + if (transferable) { + const { vertices, indices } = geo + transferable.push(vertices) + if (indices) transferable.push(indices) + } + + CSGToBuffers.cache.set(cacheKey, geo) + return geo +} + +function CSGToBuffers(csg, transferable) { + let obj + + if (csg.polygons) + obj = CSGCached(CSG2Vertices, csg, csg.polygons, transferable) + if (csg.sides && !csg.points) + obj = CSGCached(CSG2LineSegmentsVertices, csg, csg.sides, transferable) + if (csg.points) + obj = CSGCached(CSG2LineVertices, csg, csg.points, transferable) + + return obj +} +CSGToBuffers.clearCache = () => { + CSGToBuffers.cache = new WeakMap() } -CSGToBuffers.clearCache = ()=>{CSGToBuffers.cache = new WeakMap()} CSGToBuffers.clearCache() -export {CSGToBuffers} \ No newline at end of file +export { CSGToBuffers } diff --git a/app/web/src/helpers/cadPackages/index.ts b/app/web/src/helpers/cadPackages/index.ts index 4b880c9..145717e 100644 --- a/app/web/src/helpers/cadPackages/index.ts +++ b/app/web/src/helpers/cadPackages/index.ts @@ -5,7 +5,7 @@ import openscad from './openScadController' import cadquery from './cadQueryController' import jscad from './jsCadController' -export const cadPackages: {[key in CadPackage]: DefaultKernelExport} = { +export const cadPackages: { [key in CadPackage]: DefaultKernelExport } = { openscad, cadquery, jscad, diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index dd686f9..05c98a9 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -1,46 +1,73 @@ -import { RenderArgs, DefaultKernelExport, createUnhealthyResponse, createHealthyResponse } from './common' -import { MeshPhongMaterial, LineBasicMaterial, BufferGeometry , BufferAttribute, Line, LineSegments, Color, Mesh, Group} from 'three/build/three.module' - +import { + RenderArgs, + DefaultKernelExport, + createUnhealthyResponse, + createHealthyResponse, +} from './common' +import { + MeshPhongMaterial, + LineBasicMaterial, + BufferGeometry, + BufferAttribute, + Line, + LineSegments, + Color, + Mesh, + Group, +} from 'three/build/three.module' const materials = { - mesh: { - def: new MeshPhongMaterial( { color: 0x0084d1, flatShading: true } ), - material: (params)=>new MeshPhongMaterial(params), - }, - line: { - def: new LineBasicMaterial( { color: 0x0000ff } ), - material: ({color,opacity,transparent})=>new LineBasicMaterial({color,opacity,transparent}), - }, - lines:null + mesh: { + def: new MeshPhongMaterial({ color: 0x0084d1, flatShading: true }), + material: (params) => new MeshPhongMaterial(params), + }, + line: { + def: new LineBasicMaterial({ color: 0x0000ff }), + material: ({ color, opacity, transparent }) => + new LineBasicMaterial({ color, opacity, transparent }), + }, + lines: null, } materials.lines = materials.line -function CSG2Object3D(obj){ - const {vertices, indices, color, transforms} = obj +function CSG2Object3D(obj) { + const { vertices, indices, color, transforms } = obj - let materialDef = materials[obj.type] - if(!materialDef){ - console.error('Can not hangle object type: '+obj.type, obj) - return null + const materialDef = materials[obj.type] + if (!materialDef) { + console.error('Can not hangle object type: ' + obj.type, obj) + return null } - let material = materialDef.def - if(color){ - let c = color - material = new materialDef.material({ color: new Color(c[0],c[1],c[2]), flatShading: true, opacity: c[3] === void 0 ? 1:c[3], transparent: c[3] != 1 && c[3] !== void 0}) - } + let material = materialDef.def + if (color) { + const c = color + material = new materialDef.material({ + color: new Color(c[0], c[1], c[2]), + flatShading: true, + opacity: c[3] === void 0 ? 1 : c[3], + transparent: c[3] != 1 && c[3] !== void 0, + }) + } - var geo = new BufferGeometry() - geo.setAttribute('position', new BufferAttribute(vertices,3)) + const geo = new BufferGeometry() + geo.setAttribute('position', new BufferAttribute(vertices, 3)) - var mesh; - switch(obj.type){ - case 'mesh': geo.setIndex(new BufferAttribute(indices,1)); mesh = new THREE.Mesh(geo, material); break; - case 'line': mesh = new Line(geo, material); break; - case 'lines': mesh = new LineSegments(geo, material); break; - } - if(transforms) mesh.applyMatrix4({elements:transforms}) - return mesh + let mesh + switch (obj.type) { + case 'mesh': + geo.setIndex(new BufferAttribute(indices, 1)) + mesh = new THREE.Mesh(geo, material) + break + case 'line': + mesh = new Line(geo, material) + break + case 'lines': + mesh = new LineSegments(geo, material) + break + } + if (transforms) mesh.applyMatrix4({ elements: transforms }) + return mesh } let scriptWorker @@ -48,8 +75,8 @@ const scriptUrl = '/demo-worker.js' let resolveReference = null let response = null -const callResolve = ()=>{ - if(resolveReference) resolveReference() +const callResolve = () => { + if (resolveReference) resolveReference() resolveReference } @@ -57,10 +84,9 @@ export const render: DefaultKernelExport['render'] = async ({ code, settings, }: RenderArgs) => { - - if(!scriptWorker){ + if (!scriptWorker) { const baseURI = document.baseURI.toString() - const script =`let baseURI = '${baseURI}' + const script = `let baseURI = '${baseURI}' importScripts(new URL('${scriptUrl}',baseURI)) let worker = jscadWorker({ baseURI: baseURI, @@ -70,18 +96,21 @@ let worker = jscadWorker({ }) self.addEventListener('message', (e)=>worker.postMessage(e.data)) ` - let blob = new Blob([script],{type: 'text/javascript'}) + const blob = new Blob([script], { type: 'text/javascript' }) scriptWorker = new Worker(window.URL.createObjectURL(blob)) - scriptWorker.addEventListener('message',(e)=>{ + scriptWorker.addEventListener('message', (e) => { console.log('message from worker', e.data) - let data = e.data - if(data.action == 'entities'){ - if(data.error){ - response = createUnhealthyResponse( new Date(),data.error ) - }else{ - let group = new Group() - data.entities.map(CSG2Object3D).filter(o=>o).forEach(o=>group.add(o)) - response = createHealthyResponse( { + const data = e.data + if (data.action == 'entities') { + if (data.error) { + response = createUnhealthyResponse(new Date(), data.error) + } else { + const group = new Group() + data.entities + .map(CSG2Object3D) + .filter((o) => o) + .forEach((o) => group.add(o)) + response = createHealthyResponse({ type: 'geometry', data: group, consoleMessage: data.scriptStats, @@ -94,11 +123,16 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) callResolve() response = null - scriptWorker.postMessage({action:'init', baseURI, alias:[]}) + scriptWorker.postMessage({ action: 'init', baseURI, alias: [] }) } - scriptWorker.postMessage({action:'runScript', worker:'script', script:code, url:'jscad_script' }) + scriptWorker.postMessage({ + action: 'runScript', + worker: 'script', + script: code, + url: 'jscad_script', + }) - let waitResult = new Promise(resolve=>{ + const waitResult = new Promise((resolve) => { resolveReference = resolve }) diff --git a/app/web/src/helpers/hooks/useIdeState.ts b/app/web/src/helpers/hooks/useIdeState.ts index 0acd810..9b671be 100644 --- a/app/web/src/helpers/hooks/useIdeState.ts +++ b/app/web/src/helpers/hooks/useIdeState.ts @@ -11,7 +11,7 @@ function withThunk(dispatch, getState) { export type CadPackage = 'openscad' | 'cadquery' | 'jscad' -const initCodeMap: {[key in CadPackage]: string} = { +const initCodeMap: { [key in CadPackage]: string } = { openscad: `// involute donut // ^ first comment is used for download title (i.e "involute-donut.stl") @@ -42,7 +42,7 @@ result = (cq.Workplane().circle(diam).extrude(20.0) show_object(result) `, -jscad: ` + jscad: ` const { booleans, colors, primitives } = require('@jscad/modeling') // modeling comes from the included MODELING library const { intersect, subtract } = booleans @@ -68,7 +68,7 @@ const main = ({scale=1}) => { return [transpCube, star2D, line2D, ...logo] } module.exports = {main} -` +`, } const codeStorageKey = 'Last-editor-code' From 43477d33ccf8dc35568ae1462c6bc842d9aa799c Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 17:15:07 +1000 Subject: [PATCH 19/26] useEntities directly --- .../src/components/IdeViewer/IdeViewer.tsx | 21 ++++--------------- .../helpers/cadPackages/jsCadController.ts | 11 ++-------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/app/web/src/components/IdeViewer/IdeViewer.tsx b/app/web/src/components/IdeViewer/IdeViewer.tsx index 15e0175..8930b9f 100644 --- a/app/web/src/components/IdeViewer/IdeViewer.tsx +++ b/app/web/src/components/IdeViewer/IdeViewer.tsx @@ -10,12 +10,9 @@ import { TextureLoader } from 'three/src/loaders/TextureLoader' const loader = new TextureLoader() const colorMap = loader.load(texture) -let lastGroup - extend({ OrbitControls }) function Asset({ geometry: incomingGeo }) { - const state = useThree() const mesh = useRef() const ref = useRef({}) useLayoutEffect(() => { @@ -25,20 +22,10 @@ function Asset({ geometry: incomingGeo }) { }, [incomingGeo]) if (!incomingGeo) return null - const groupData = incomingGeo.children ? incomingGeo : null - if (lastGroup && lastGroup != groupData) { - state.scene.remove(lastGroup) - lastGroup.children.forEach((c) => c?.geometry?.dispose()) - // returning does not add the new group to the scene - // there is probably some useRef magic that would make this work, but I don't have time to reseach it - /// FIXME - do this properly with useRef or other react magic - if (groupData) state.scene.add(groupData) - } - lastGroup = groupData - - if (groupData) return - - if (incomingGeo.children) return + if (incomingGeo.length) + return incomingGeo.map((shape, index) => ( + + )) return ( diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 05c98a9..417ba6b 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -57,7 +57,7 @@ function CSG2Object3D(obj) { switch (obj.type) { case 'mesh': geo.setIndex(new BufferAttribute(indices, 1)) - mesh = new THREE.Mesh(geo, material) + mesh = new Mesh(geo, material) break case 'line': mesh = new Line(geo, material) @@ -99,20 +99,14 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) const blob = new Blob([script], { type: 'text/javascript' }) scriptWorker = new Worker(window.URL.createObjectURL(blob)) scriptWorker.addEventListener('message', (e) => { - console.log('message from worker', e.data) const data = e.data if (data.action == 'entities') { if (data.error) { response = createUnhealthyResponse(new Date(), data.error) } else { - const group = new Group() - data.entities - .map(CSG2Object3D) - .filter((o) => o) - .forEach((o) => group.add(o)) response = createHealthyResponse({ type: 'geometry', - data: group, + data: [...data.entities.map(CSG2Object3D).filter((o) => o)], consoleMessage: data.scriptStats, date: new Date(), }) @@ -138,7 +132,6 @@ self.addEventListener('message', (e)=>worker.postMessage(e.data)) await waitResult resolveReference = null - console.log('response', response) return response } From 67d5d76d67a59c943e2f17b6a914d7a4fb16faac Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Sun, 1 Aug 2021 10:47:58 +0200 Subject: [PATCH 20/26] Delete CSGToBuffers.js --- .../src/helpers/cadPackages/CSGToBuffers.js | 109 ------------------ 1 file changed, 109 deletions(-) delete mode 100644 app/web/src/helpers/cadPackages/CSGToBuffers.js diff --git a/app/web/src/helpers/cadPackages/CSGToBuffers.js b/app/web/src/helpers/cadPackages/CSGToBuffers.js deleted file mode 100644 index 72ca689..0000000 --- a/app/web/src/helpers/cadPackages/CSGToBuffers.js +++ /dev/null @@ -1,109 +0,0 @@ -const setPoints = (points, p, i) => { - points[i++] = p[0] - points[i++] = p[1] - points[i++] = p[2] || 0 -} - -function CSG2Vertices(csg) { - let idx = 0 - - let vLen = 0, - iLen = 0 - for (let poly of csg.polygons) { - let len = poly.vertices.length - vLen += len * 3 - iLen += 3 * (len - 2) - } - const vertices = new Float32Array(vLen) - const indices = vLen > 65535 ? new Uint32Array(iLen) : new Uint16Array(iLen) - - let vertOffset = 0 - let indOffset = 0 - let posOffset = 0 - let first = 0 - for (let poly of csg.polygons) { - let arr = poly.vertices - let len = arr.length - first = posOffset - vertices.set(arr[0], vertOffset) - vertOffset += 3 - vertices.set(arr[1], vertOffset) - vertOffset += 3 - posOffset += 2 - for (let i = 2; i < len; i++) { - vertices.set(arr[i], vertOffset) - - indices[indOffset++] = first - indices[indOffset++] = first + i - 1 - indices[indOffset++] = first + i - - vertOffset += 3 - posOffset += 1 - } - } - return { vertices, indices, type: 'mesh' } -} - -function CSG2LineVertices(csg) { - let vLen = csg.points.length * 3 - if (csg.isClosed) vLen += 3 - - var vertices = new Float32Array(vLen) - - csg.points.forEach((p, idx) => setPoints(vertices, p, idx * 3)) - - if (csg.isClosed) { - setPoints(vertices, csg.points[0], vertices.length - 3) - } - return { vertices, type: 'line' } -} - -function CSG2LineSegmentsVertices(csg) { - let vLen = csg.sides.length * 6 - - var vertices = new Float32Array(vLen) - csg.sides.forEach((side, idx) => { - let i = idx * 6 - setPoints(vertices, side[0], i) - setPoints(vertices, side[1], i + 3) - }) - return { vertices, type: 'lines' } -} - -function CSGCached(func, data, cacheKey, transferable) { - cacheKey = cacheKey || data - - let geo = CSGToBuffers.cache.get(cacheKey) - if (geo) return geo - - geo = func(data) - - // fill transferable array for postMessage optimization - if (transferable) { - const { vertices, indices } = geo - transferable.push(vertices) - if (indices) transferable.push(indices) - } - - CSGToBuffers.cache.set(cacheKey, geo) - return geo -} - -function CSGToBuffers(csg, transferable) { - let obj - - if (csg.polygons) - obj = CSGCached(CSG2Vertices, csg, csg.polygons, transferable) - if (csg.sides && !csg.points) - obj = CSGCached(CSG2LineSegmentsVertices, csg, csg.sides, transferable) - if (csg.points) - obj = CSGCached(CSG2LineVertices, csg, csg.points, transferable) - - return obj -} -CSGToBuffers.clearCache = () => { - CSGToBuffers.cache = new WeakMap() -} -CSGToBuffers.clearCache() - -export { CSGToBuffers } From cedad90513a5c201d94d0ad532f82946ed42ac88 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 19:53:05 +1000 Subject: [PATCH 21/26] update import style --- app/web/src/helpers/cadPackages/jsCadController.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 417ba6b..3091ba7 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -13,8 +13,7 @@ import { LineSegments, Color, Mesh, - Group, -} from 'three/build/three.module' +} from 'three' const materials = { mesh: { From 39cbdc749be4b3dd528338ce17950de78b96f596 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 20:39:26 +1000 Subject: [PATCH 22/26] get deployments working again --- app/api/package.json | 2 - ...-generator.ts => og-image-generator.ts.md} | 0 app/yarn.lock | 49 +------------------ 3 files changed, 1 insertion(+), 50 deletions(-) rename app/api/src/services/{og-image-generator.ts => og-image-generator.ts.md} (100%) diff --git a/app/api/package.json b/app/api/package.json index 354a796..e6ae773 100644 --- a/app/api/package.json +++ b/app/api/package.json @@ -5,7 +5,6 @@ "dependencies": { "@redwoodjs/api": "^0.34.1", "@sentry/node": "^6.5.1", - "chrome-aws-lambda": "^10.1.0", "cloudinary": "^1.23.0", "human-id": "^2.0.1", "nodemailer": "^6.6.2", @@ -13,7 +12,6 @@ }, "devDependencies": { "@netlify/functions": "^0.7.2", - "puppeteer": "^10.1.0", "@types/nodemailer": "^6.4.2" } } diff --git a/app/api/src/services/og-image-generator.ts b/app/api/src/services/og-image-generator.ts.md similarity index 100% rename from app/api/src/services/og-image-generator.ts rename to app/api/src/services/og-image-generator.ts.md diff --git a/app/yarn.lock b/app/yarn.lock index 92f6075..0def46b 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -6483,13 +6483,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -chrome-aws-lambda@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/chrome-aws-lambda/-/chrome-aws-lambda-10.1.0.tgz#ac43b4cdfc1fbb2275c62effada560858099501e" - integrity sha512-NZQVf+J4kqG4sVhRm3WNmOfzY0OtTSm+S8rg77pwePa9RCYHzhnzRs8YvNI6L9tALIW6RpmefWiPURt3vURXcw== - dependencies: - lambdafs "^2.0.3" - chrome-trace-event@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" @@ -11969,13 +11962,6 @@ klona@^2.0.3: resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0" integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA== -lambdafs@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/lambdafs/-/lambdafs-2.0.3.tgz#f2acc53cf4862d29f1df654c327864b4faeb1d4a" - integrity sha512-5YWwZA/QKk09GdfcJ/ABVO+bpFoGlnTBa5jmyM8Kt9yIzl2lDDVBPLK+Aenq2UEcuDpqxXIYI5zLB7VZNepTrg== - dependencies: - tar-fs "^2.1.1" - language-subtag-registry@~0.3.2: version "0.3.21" resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" @@ -12832,11 +12818,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -14822,24 +14803,6 @@ puppeteer-core@^10.1.0: unbzip2-stream "1.3.3" ws "7.4.6" -puppeteer@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-10.1.0.tgz#6ee1d7e30401a967f4403bd42ace9e51e399504f" - integrity sha512-bsyDHbFBvbofZ63xqF7hMhuKBX1h4WsqFIAoh1GuHr/Y9cewh+EFNAOdqWSkQRHLiBU/MY6M+8PUnXXjAPtuSg== - dependencies: - debug "4.3.1" - devtools-protocol "0.0.883894" - extract-zip "2.0.1" - https-proxy-agent "5.0.0" - node-fetch "2.6.1" - pkg-dir "4.2.0" - progress "2.0.1" - proxy-from-env "1.1.0" - rimraf "3.0.2" - tar-fs "2.0.0" - unbzip2-stream "1.3.3" - ws "7.4.6" - purgecss@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/purgecss/-/purgecss-4.0.3.tgz#8147b429f9c09db719e05d64908ea8b672913742" @@ -17063,17 +17026,7 @@ tar-fs@2.0.0: pump "^3.0.0" tar-stream "^2.0.0" -tar-fs@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" - integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== - dependencies: - chownr "^1.1.1" - mkdirp-classic "^0.5.2" - pump "^3.0.0" - tar-stream "^2.1.4" - -tar-stream@^2.0.0, tar-stream@^2.1.2, tar-stream@^2.1.4: +tar-stream@^2.0.0, tar-stream@^2.1.2: version "2.2.0" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== From 5e14ad0829764eed825660201068044c7aeb1334 Mon Sep 17 00:00:00 2001 From: Kurt Hutten Date: Sun, 1 Aug 2021 21:13:19 +1000 Subject: [PATCH 23/26] fix constructor bug --- app/web/src/helpers/cadPackages/jsCadController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/web/src/helpers/cadPackages/jsCadController.ts b/app/web/src/helpers/cadPackages/jsCadController.ts index 3091ba7..e26f92e 100644 --- a/app/web/src/helpers/cadPackages/jsCadController.ts +++ b/app/web/src/helpers/cadPackages/jsCadController.ts @@ -41,7 +41,7 @@ function CSG2Object3D(obj) { let material = materialDef.def if (color) { const c = color - material = new materialDef.material({ + material = materialDef.material({ color: new Color(c[0], c[1], c[2]), flatShading: true, opacity: c[3] === void 0 ? 1 : c[3], From 7178313c2eae73620aef26dbd111d124cd35acd4 Mon Sep 17 00:00:00 2001 From: Davor Hrg Date: Mon, 2 Aug 2021 13:39:18 +0200 Subject: [PATCH 24/26] Update helpers.ts --- app/web/src/components/EditorMenu/helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/web/src/components/EditorMenu/helpers.ts b/app/web/src/components/EditorMenu/helpers.ts index 2393ac7..0ced278 100644 --- a/app/web/src/components/EditorMenu/helpers.ts +++ b/app/web/src/components/EditorMenu/helpers.ts @@ -36,7 +36,7 @@ export const makeStlDownloadHandler = }: makeStlDownloadHandlerArgs) => () => { const makeStlBlobFromMesh = flow( - (mesh) => new Scene().add(mesh), + (...meshes) => new Scene().add(...meshes), (scene) => new STLExporter().parse(scene), (stl) => new Blob([stl], { @@ -60,7 +60,7 @@ export const makeStlDownloadHandler = ) { saveFile(makeStlBlobFromGeo(geometry)) } else if (ideType == 'jscad') { - saveFile(makeStlBlobFromMesh(geometry)) + saveFile(makeStlBlobFromMesh(...geometry)) } else { thunkDispatch((dispatch, getState) => { const state = getState() From a06e71291fe2327e16aadf1f2f16edd67f21d515 Mon Sep 17 00:00:00 2001 From: Iulian Onofrei <6d0847b9@opayq.com> Date: Tue, 3 Aug 2021 16:53:27 +0300 Subject: [PATCH 25/26] Fix typo in docs page --- docs/docs/general-cadhub/external-resource-url.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/general-cadhub/external-resource-url.mdx b/docs/docs/general-cadhub/external-resource-url.mdx index bd2d41d..ba6aaf5 100644 --- a/docs/docs/general-cadhub/external-resource-url.mdx +++ b/docs/docs/general-cadhub/external-resource-url.mdx @@ -24,7 +24,7 @@ Open the IDE for the Cad package to match your script, in this case OpenSCAD. -Click the share button in the top right, then select the "external srcipt" tab. +Click the share button in the top right, then select the "external script" tab. From b6cb22ed2ded45707546db1406c265ab276fde81 Mon Sep 17 00:00:00 2001 From: Iulian Onofrei <6d0847b9@opayq.com> Date: Tue, 3 Aug 2021 16:58:34 +0300 Subject: [PATCH 26/26] Fix incorrect docs and blog edit links --- docs/docusaurus.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index d750155..07c9e8a 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -94,12 +94,12 @@ module.exports = { docs: { sidebarPath: require.resolve('./sidebars.js'), editUrl: - 'https://github.com/facebook/docusaurus/edit/master/website/', + 'https://github.com/Irev-Dev/cadhub/blob/main/docs/', }, blog: { showReadingTime: true, editUrl: - 'https://github.com/facebook/docusaurus/edit/master/website/blog/', + 'https://github.com/Irev-Dev/cadhub/blob/main/docs/', }, theme: { customCss: require.resolve('./src/css/custom.css'),