A library beside the canvas
I placed reusable modules beside the workspace, keeping the available building blocks close to where they are used.
levelyst-workbench.tsxDrop → create → select
1070const getViewportWorldCenter = useCallback(() => {
1071 const bounds = editorSurfaceRef.current?.getBoundingClientRect()
1072 if (!bounds) {
1073 return { x: WORLD_WIDTH / 2, y: WORLD_HEIGHT / 2 }
1074 }
1075 const width = bounds.width
1076 const height = bounds.height
1077 return deriveViewportWorldCenter(canvasViewport, width, height)
1078}, [canvasViewport])
1079
1080const addNodeFromTemplate = useCallback((typeId: string, x: number, y: number) => {
1081 if (isReadOnlyDemo) {
1082 showReadOnlyDemoNotice()
1083 return
1084 }
1085
1086 const template = moduleTemplateMap.get(typeId)
1087 if (!template) return
1088 const node = createNodeFromTemplate(template, x, y)
1089 setNodes((prev) => [...prev, node])
1090 setSelectedNodeId(node.id)
1091 setSelectedNodeIds([node.id])
1092}, [isReadOnlyDemo, showReadOnlyDemoNotice])
1093
1094const autoPlaceByTypeIds = useCallback((typeIds: string[]) => {
1095 const center = getViewportWorldCenter()
1096 setNodes((prev) => {
1097 const existingTypes = new Set(prev.map((node) => node.typeId))
1098 const queuedTypeIds = typeIds.filter((typeId) => moduleTemplateMap.has(typeId) && !existingTypes.has(typeId))
1099 const next = [...prev]
1100 queuedTypeIds.forEach((typeId, index) => {
1101 const template = moduleTemplateMap.get(typeId)
1102 if (!template) return
1103 existingTypes.add(typeId)
1104 const { x, y } = getClusterNodePosition(index, queuedTypeIds.length, center.x, center.y)
1105 next.push(createNodeFromTemplate(template, x, y))
1106 })
1107 return next
1108 })
1109}, [getViewportWorldCenter])
Turn a drop into a node
The drop handler creates, adds, and selects a canvas node.
- Create
- Use the module template and drop position.
- Add
- Keep the existing nodes and append this one.
- Select
- Make the new node the current selection.
Source: components/editor-v2/levelyst-workbench.tsx · addNodeFromTemplate excerpt
Modules placed for editing
Both modules are now on the canvas. The last drop is selected; placement alone does not connect the nodes or resolve their dependencies.