diff --git a/src/App.tsx b/src/App.tsx
index 09845bd0e..180fe3363 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -15,6 +15,10 @@ import {
} from './editor/highlightextension'
import { useStore } from './useStore'
import { isOverlapping } from './lib/utils'
+import { Toolbar } from './Toolbar'
+import { BasePlanes } from './components/BasePlanes'
+import { SketchPlane } from './components/SketchPlane'
+import { Logs } from './components/Logs'
const _code = `sketch mySketch {
path myPath = lineTo(0,1)
@@ -29,15 +33,25 @@ const OrrthographicCamera = OrthographicCamera as any
function App() {
const cam = useRef()
const [code, setCode] = useState(_code)
- const { editorView, setEditorView, setSelectionRange, selectionRange } =
- useStore(
- ({ editorView, setEditorView, setSelectionRange, selectionRange }) => ({
- editorView,
- setEditorView,
- setSelectionRange,
- selectionRange,
- })
- )
+ const {
+ editorView,
+ setEditorView,
+ setSelectionRange,
+ selectionRange,
+ guiMode,
+ setGuiMode,
+ removeError,
+ addLog,
+ } = useStore((s) => ({
+ editorView: s.editorView,
+ setEditorView: s.setEditorView,
+ setSelectionRange: s.setSelectionRange,
+ selectionRange: s.selectionRange,
+ guiMode: s.guiMode,
+ setGuiMode: s.setGuiMode,
+ removeError: s.removeError,
+ addLog: s.addLog,
+ }))
// const onChange = React.useCallback((value: string, viewUpdate: ViewUpdate) => {
const onChange = (value: string, viewUpdate: ViewUpdate) => {
setCode(value)
@@ -60,9 +74,21 @@ function App() {
>([])
useEffect(() => {
try {
+ if (!code) {
+ setGeoArray([])
+ removeError()
+ return
+ }
const tokens = lexer(code)
const ast = abstractSyntaxTree(tokens)
- const programMemory = executor(ast)
+ const programMemory = executor(ast, {
+ root: {
+ log: (a: any) => {
+ addLog(a)
+ },
+ },
+ _sketch: [],
+ })
const geos: { geo: BufferGeometry; sourceRange: [number, number] }[] =
programMemory.root.mySketch
.map(
@@ -76,14 +102,18 @@ function App() {
)
.filter((a: any) => !!a.geo)
setGeoArray(geos)
+ removeError()
console.log(programMemory)
- } catch (e) {
+ } catch (e: any) {
+ setGuiMode({ mode: 'codeError' })
console.log(e)
+ addLog(e)
}
}, [code])
return (
+
viewer
-
-
+
+
+
+
+
+ {guiMode.mode === 'codeError' && (
+
yo
+ )}
diff --git a/src/Toolbar.tsx b/src/Toolbar.tsx
new file mode 100644
index 000000000..9bd364341
--- /dev/null
+++ b/src/Toolbar.tsx
@@ -0,0 +1,27 @@
+import { useStore } from './useStore'
+
+export const Toolbar = () => {
+ const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({
+ guiMode,
+ setGuiMode,
+ }))
+ return (
+
+ {guiMode.mode === 'default' && (
+
+ )}
+ {guiMode.mode !== 'default' && (
+
+ )}
+
+ )
+}
diff --git a/src/components/BasePlanes.tsx b/src/components/BasePlanes.tsx
new file mode 100644
index 000000000..b1ec89dde
--- /dev/null
+++ b/src/components/BasePlanes.tsx
@@ -0,0 +1,74 @@
+import { useState } from 'react'
+import { DoubleSide } from 'three'
+import { useStore } from '../useStore'
+import { Intersection } from '@react-three/fiber'
+
+const opacity = 0.1
+
+export const BasePlanes = () => {
+ const [axisIndex, setAxisIndex] = useState
(null)
+ const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({
+ guiMode,
+ setGuiMode,
+ }))
+
+ const onPointerEvent = ({
+ intersections,
+ }: {
+ intersections: Intersection[]
+ }) => {
+ if (!intersections.length) {
+ setAxisIndex(null)
+ return
+ }
+ let closestIntersection = intersections[0]
+ intersections.forEach((intersection) => {
+ if (intersection.distance < closestIntersection.distance)
+ closestIntersection = intersection
+ })
+ const smallestIndex = Number(closestIntersection.eventObject.name)
+ setAxisIndex(smallestIndex)
+ }
+ const onClick = () => {
+ if (guiMode.mode !== 'sketch') {
+ return null
+ }
+ if (guiMode.sketchMode !== 'selectFace') {
+ return null
+ }
+ setGuiMode({
+ mode: 'sketch',
+ sketchMode: 'points',
+ axis: axisIndex === 0 ? 'yz' : axisIndex === 1 ? 'xy' : 'xz',
+ })
+ }
+ if (guiMode.mode !== 'sketch') {
+ return null
+ }
+ if (guiMode.sketchMode !== 'selectFace') {
+ return null
+ }
+ return (
+ <>
+ {Array.from({ length: 3 }).map((_, index) => (
+
+
+
+
+ ))}
+ >
+ )
+}
diff --git a/src/components/Logs.tsx b/src/components/Logs.tsx
new file mode 100644
index 000000000..b0968586e
--- /dev/null
+++ b/src/components/Logs.tsx
@@ -0,0 +1,34 @@
+import { useEffect } from 'react'
+import { useStore } from '../useStore'
+
+export const Logs = () => {
+ const { logs, resetLogs } = useStore(({ logs, resetLogs }) => ({
+ logs,
+ resetLogs,
+ }))
+ useEffect(() => {
+ const element = document.querySelector('.console-tile')
+ if (element) {
+ element.scrollTop = element.scrollHeight - element.clientHeight
+ }
+ }, [logs])
+ return (
+
+
+
+
+ {logs.map((msg, index) => {
+ return (
+
+
+ {'- '}
+ {String(msg)}
+
+
+ )
+ })}
+
+
+
+ )
+}
diff --git a/src/components/SketchPlane.tsx b/src/components/SketchPlane.tsx
new file mode 100644
index 000000000..599b9961d
--- /dev/null
+++ b/src/components/SketchPlane.tsx
@@ -0,0 +1,25 @@
+import { useStore } from '../useStore'
+
+export const SketchPlane = () => {
+ const { setGuiMode, guiMode } = useStore(({ guiMode, setGuiMode }) => ({
+ guiMode,
+ setGuiMode,
+ }))
+ if (guiMode.mode !== 'sketch') {
+ return null
+ }
+ if (guiMode.sketchMode !== 'points') {
+ return null
+ }
+
+ const ninty = Math.PI / 2
+ const rotation: [number, number, number] = [0, 0, 0]
+ if (guiMode.axis === 'yz') {
+ rotation[0] = ninty
+ } else if (guiMode.axis === 'xy') {
+ rotation[1] = ninty
+ } else if (guiMode.axis === 'xz') {
+ rotation[2] = ninty
+ }
+ return
+}
diff --git a/src/useStore.ts b/src/useStore.ts
index ea6ba030d..c2bd8397c 100644
--- a/src/useStore.ts
+++ b/src/useStore.ts
@@ -3,6 +3,23 @@ import { addLineHighlight, EditorView } from './editor/highlightextension'
export type Range = [number, number]
+type GuiModes =
+ | {
+ mode: 'default'
+ }
+ | {
+ mode: 'sketch'
+ sketchMode: 'points'
+ axis: 'xy' | 'xz' | 'yz'
+ }
+ | {
+ mode: 'sketch'
+ sketchMode: 'selectFace'
+ }
+ | {
+ mode: 'codeError'
+ }
+
interface StoreState {
editorView: EditorView | null
setEditorView: (editorView: EditorView) => void
@@ -10,6 +27,13 @@ interface StoreState {
setHighlightRange: (range: Range) => void
selectionRange: [number, number]
setSelectionRange: (range: Range) => void
+ guiMode: GuiModes
+ lastGuiMode: GuiModes
+ setGuiMode: (guiMode: GuiModes) => void
+ removeError: () => void
+ logs: string[]
+ addLog: (log: string) => void
+ resetLogs: () => void
}
export const useStore = create()((set, get) => ({
@@ -29,4 +53,25 @@ export const useStore = create()((set, get) => ({
setSelectionRange: (selectionRange) => {
set({ selectionRange })
},
+ guiMode: { mode: 'default' },
+ lastGuiMode: { mode: 'default' },
+ setGuiMode: (guiMode) => {
+ const lastGuiMode = get().guiMode
+ set({ guiMode })
+ set({ lastGuiMode })
+ },
+ removeError: () => {
+ const lastGuiMode = get().lastGuiMode
+ const currentGuiMode = get().guiMode
+ if (currentGuiMode.mode === 'codeError') {
+ set({ guiMode: lastGuiMode })
+ }
+ },
+ logs: [],
+ addLog: (log) => {
+ set((state) => ({ logs: [...state.logs, log] }))
+ },
+ resetLogs: () => {
+ set({ logs: [] })
+ },
}))