diff --git a/.gitignore b/.gitignore
index 4580eda2..2c627d0b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -53,3 +53,9 @@ tarpaulin-report.html
tarpaulin-report.json
**/tarpaulin-report.html
**/tarpaulin-report.json
+
+# superpowers 작업 산출물(플랜 문서 등) — 저장소에 커밋하지 않는다.
+docs/superpowers/
+
+# superpowers 로컬 작업 디렉터리.
+.superpowers/
diff --git a/apps/landing/package.json b/apps/landing/package.json
index e0c1ffe9..71f959ff 100644
--- a/apps/landing/package.json
+++ b/apps/landing/package.json
@@ -17,6 +17,7 @@
"braillify": "workspace:*",
"clsx": "^2.1.1",
"katex": "^0.17.0",
+ "mathlive": "^0.110.0",
"next": "16.2.10",
"react": "^19.2.7",
"react-dom": "^19.2.7",
diff --git a/apps/landing/public/mathlive/LICENSE.txt b/apps/landing/public/mathlive/LICENSE.txt
new file mode 100644
index 00000000..bf729484
--- /dev/null
+++ b/apps/landing/public/mathlive/LICENSE.txt
@@ -0,0 +1,22 @@
+The KaTeX_*.woff2 font files in ./fonts are redistributed from the MathLive
+package (https://github.com/arnog/mathlive) under the MIT License below.
+
+Copyright (c) 2017 - present Arno Gourdol. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_AMS-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_AMS-Regular.woff2
new file mode 100644
index 00000000..0acaaff0
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_AMS-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Caligraphic-Bold.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Caligraphic-Bold.woff2
new file mode 100644
index 00000000..f390922e
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Caligraphic-Bold.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Caligraphic-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Caligraphic-Regular.woff2
new file mode 100644
index 00000000..75344a1f
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Caligraphic-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Fraktur-Bold.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Fraktur-Bold.woff2
new file mode 100644
index 00000000..395f28be
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Fraktur-Bold.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Fraktur-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Fraktur-Regular.woff2
new file mode 100644
index 00000000..735f6948
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Fraktur-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Main-Bold.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Main-Bold.woff2
new file mode 100644
index 00000000..ab2ad21d
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Main-Bold.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Main-BoldItalic.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Main-BoldItalic.woff2
new file mode 100644
index 00000000..5931794d
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Main-BoldItalic.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Main-Italic.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Main-Italic.woff2
new file mode 100644
index 00000000..b50920e1
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Main-Italic.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Main-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Main-Regular.woff2
new file mode 100644
index 00000000..eb24a7ba
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Main-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Math-BoldItalic.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Math-BoldItalic.woff2
new file mode 100644
index 00000000..29657023
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Math-BoldItalic.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Math-Italic.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Math-Italic.woff2
new file mode 100644
index 00000000..215c143f
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Math-Italic.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Bold.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Bold.woff2
new file mode 100644
index 00000000..cfaa3bda
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Bold.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Italic.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Italic.woff2
new file mode 100644
index 00000000..349c06dc
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Italic.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Regular.woff2
new file mode 100644
index 00000000..a90eea85
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_SansSerif-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Script-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Script-Regular.woff2
new file mode 100644
index 00000000..b3048fc1
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Script-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Size1-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Size1-Regular.woff2
new file mode 100644
index 00000000..c5a8462f
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Size1-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Size2-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Size2-Regular.woff2
new file mode 100644
index 00000000..e1bccfe2
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Size2-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Size3-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Size3-Regular.woff2
new file mode 100644
index 00000000..249a2866
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Size3-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Size4-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Size4-Regular.woff2
new file mode 100644
index 00000000..680c1308
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Size4-Regular.woff2 differ
diff --git a/apps/landing/public/mathlive/fonts/KaTeX_Typewriter-Regular.woff2 b/apps/landing/public/mathlive/fonts/KaTeX_Typewriter-Regular.woff2
new file mode 100644
index 00000000..771f1af7
Binary files /dev/null and b/apps/landing/public/mathlive/fonts/KaTeX_Typewriter-Regular.woff2 differ
diff --git a/apps/landing/src/app/DemoArrow.tsx b/apps/landing/src/app/DemoArrow.tsx
new file mode 100644
index 00000000..dd5f49f2
--- /dev/null
+++ b/apps/landing/src/app/DemoArrow.tsx
@@ -0,0 +1,24 @@
+import { Flex, Image } from '@devup-ui/react'
+
+/** 입력 박스와 출력 박스 사이의 방향 화살표. 한글·수학 데모가 공유한다. */
+export function DemoArrow() {
+ return (
+
+ {/* 데스크톱에서만 보이는 원형 장식. 화살표와 중복 안내되지 않도록 장식으로 둔다. */}
+
+
+
+ )
+}
diff --git a/apps/landing/src/app/DemoHeading.tsx b/apps/landing/src/app/DemoHeading.tsx
new file mode 100644
index 00000000..943869f9
--- /dev/null
+++ b/apps/landing/src/app/DemoHeading.tsx
@@ -0,0 +1,29 @@
+import { Box, Flex, Text } from '@devup-ui/react'
+
+/** 데모 섹션 상단의 손가락 아이콘 + 안내 문구. 한글·수학 데모가 공유한다. */
+export function DemoHeading({ children }: { children: string }) {
+ return (
+
+
+
+ {children}
+
+
+ )
+}
diff --git a/apps/landing/src/app/DemoTabs.tsx b/apps/landing/src/app/DemoTabs.tsx
new file mode 100644
index 00000000..ba8fa076
--- /dev/null
+++ b/apps/landing/src/app/DemoTabs.tsx
@@ -0,0 +1,79 @@
+'use client'
+import { Box, Flex, Text, VStack } from '@devup-ui/react'
+import { useRef, useState } from 'react'
+
+import { MathTrans } from './MathTrans'
+import { Trans } from './Trans'
+
+const TABS = [
+ { key: 'korean', label: '한글' },
+ { key: 'math', label: '수학' },
+] as const
+
+type DemoMode = (typeof TABS)[number]['key']
+
+const PANEL_ID = 'demo-panel'
+const tabId = (key: DemoMode) => `demo-tab-${key}`
+
+export function DemoTabs() {
+ const [mode, setMode] = useState('korean')
+ const tabRefs = useRef<(HTMLElement | null)[]>([])
+
+ const handleKeyDown = (e: React.KeyboardEvent, index: number) => {
+ if (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return
+ e.preventDefault()
+ const dir = e.key === 'ArrowRight' ? 1 : -1
+ const next = (index + dir + TABS.length) % TABS.length
+ setMode(TABS[next].key)
+ tabRefs.current[next]?.focus()
+ }
+
+ return (
+
+
+ {TABS.map(({ key, label }, index) => (
+ {
+ tabRefs.current[index] = el
+ }}
+ aria-controls={PANEL_ID}
+ aria-selected={mode === key}
+ as="button"
+ bg={mode === key ? '$text' : 'transparent'}
+ border="1px solid $text"
+ borderRadius="1000px"
+ color={mode === key ? '$background' : '$text'}
+ cursor="pointer"
+ id={tabId(key)}
+ onClick={() => setMode(key)}
+ onKeyDown={(e) => handleKeyDown(e, index)}
+ px={['20px', null, null, '28px']}
+ py={['8px', null, null, '10px']}
+ role="tab"
+ tabIndex={mode === key ? 0 : -1}
+ type="button"
+ typography="button"
+ >
+ {label}
+
+ ))}
+
+
+ {mode === 'korean' ? : }
+
+
+ )
+}
diff --git a/apps/landing/src/app/MathTrans.tsx b/apps/landing/src/app/MathTrans.tsx
new file mode 100644
index 00000000..2496c46d
--- /dev/null
+++ b/apps/landing/src/app/MathTrans.tsx
@@ -0,0 +1,15 @@
+import { VStack } from '@devup-ui/react'
+
+import { DemoHeading } from './DemoHeading'
+import { MathTransPanel } from './MathTransPanel'
+
+export function MathTrans() {
+ return (
+
+
+ 수식도 점자가 됩니다. 수식 키보드로 입력해 수학 점역을 체험해보세요!
+
+
+
+ )
+}
diff --git a/apps/landing/src/app/MathTransInput.tsx b/apps/landing/src/app/MathTransInput.tsx
new file mode 100644
index 00000000..38cefef2
--- /dev/null
+++ b/apps/landing/src/app/MathTransInput.tsx
@@ -0,0 +1,123 @@
+'use client'
+
+import { css, Flex, Text, VStack } from '@devup-ui/react'
+import type { MathfieldElement } from 'mathlive'
+import { useEffect, useRef, useState } from 'react'
+
+import { normalizeFracBraces } from './normalizeFracBraces'
+
+declare global {
+ // 커스텀 엘리먼트를 JSX 에 등록하려면 React.JSX 네임스페이스 병합이 유일한 방법이다.
+ // oxlint-disable-next-line no-namespace
+ namespace React.JSX {
+ interface IntrinsicElements {
+ 'math-field': React.DetailedHTMLProps<
+ React.HTMLAttributes,
+ MathfieldElement
+ > & { 'math-virtual-keyboard-policy'?: 'auto' | 'manual' }
+ }
+ }
+}
+
+export function MathTransInput({
+ latex,
+ onLatexChange,
+ placeholder,
+}: {
+ latex: string
+ onLatexChange: (latex: string) => void
+ placeholder: string
+}) {
+ const [ready, setReady] = useState(false)
+ const fieldRef = useRef(null)
+
+ useEffect(() => {
+ let cancelled = false
+ import('mathlive').then(({ MathfieldElement }) => {
+ if (cancelled) return
+ MathfieldElement.fontsDirectory = '/mathlive/fonts'
+ MathfieldElement.soundsDirectory = null
+ setReady(true)
+ })
+ return () => {
+ cancelled = true
+ }
+ }, [])
+
+ useEffect(() => {
+ const field = fieldRef.current
+ if (!ready || !field) return
+ const show = () => window.mathVirtualKeyboard.show()
+ const hide = () => window.mathVirtualKeyboard.hide()
+ field.addEventListener('focusin', show)
+ field.addEventListener('focusout', hide)
+ return () => {
+ field.removeEventListener('focusin', show)
+ field.removeEventListener('focusout', hide)
+ window.mathVirtualKeyboard.hide()
+ }
+ }, [ready])
+
+ return (
+ // 폭 분배(flex)는 호출부가 맡는다. 바깥 Flex 에 padding 을 두지 않는 이유는
+ // flex-basis:0 이라도 flex 아이템의 border-box 크기가 padding 합보다 작아질 수
+ // 없어서, padding 이 있으면 그만큼 출력측 TransInput 보다 넓어지기 때문이다.
+
+ fieldRef.current?.focus()}
+ p={['16px', null, null, '40px']}
+ w="100%"
+ >
+
+ {ready && (
+
+ onLatexChange(
+ normalizeFracBraces(
+ (e.target as MathfieldElement).getValue(
+ 'latex-without-placeholders',
+ ),
+ ),
+ )
+ }
+ />
+ )}
+ {!latex && (
+
+ {placeholder}
+
+ )}
+
+
+ {latex ? `LaTeX: $${latex}$` : 'LaTeX가 자동으로 생성됩니다'}
+
+
+
+ )
+}
diff --git a/apps/landing/src/app/MathTransPanel.tsx b/apps/landing/src/app/MathTransPanel.tsx
new file mode 100644
index 00000000..c28df493
--- /dev/null
+++ b/apps/landing/src/app/MathTransPanel.tsx
@@ -0,0 +1,54 @@
+'use client'
+import { VStack } from '@devup-ui/react'
+import { useEffect, useState } from 'react'
+
+import { DemoArrow } from './DemoArrow'
+import { MathTransInput } from './MathTransInput'
+import { TransInput } from './TransInput'
+
+/** 수식 입력 → 수학 점자 출력. 상태를 쥔 부분만 클라이언트로 분리한다. */
+export function MathTransPanel() {
+ const [latex, setLatex] = useState('')
+ const [translateToUnicode, setTranslateToUnicode] = useState<
+ (input: string) => string
+ >(() => () => '')
+ useEffect(() => {
+ import('braillify').then((mod) => {
+ setTranslateToUnicode(() => (input: string) => {
+ try {
+ return mod.translateToUnicode(input)
+ } catch (e) {
+ console.error(e)
+ return '점역할 수 없는 수식이 포함되어 있습니다.'
+ }
+ })
+ })
+ }, [])
+
+ const braille = latex.trim() ? translateToUnicode(`$${latex}$`) : ''
+
+ return (
+ *:first-child, &>*:last-child': { flex: 1, minWidth: 0 },
+ }}
+ >
+
+
+
+
+ )
+}
diff --git a/apps/landing/src/app/Trans.tsx b/apps/landing/src/app/Trans.tsx
index 3d6c57d8..f02474ef 100644
--- a/apps/landing/src/app/Trans.tsx
+++ b/apps/landing/src/app/Trans.tsx
@@ -1,7 +1,9 @@
'use client'
-import { Box, Flex, Image, Text, VStack } from '@devup-ui/react'
+import { VStack } from '@devup-ui/react'
import { useEffect, useState } from 'react'
+import { DemoArrow } from './DemoArrow'
+import { DemoHeading } from './DemoHeading'
import { TransInput } from './TransInput'
export function Trans() {
@@ -26,30 +28,10 @@ export function Trans() {
const [translationFocused, setTranslationFocused] = useState(false)
return (
-
-
-
-
- 직접 입력해 실시간 점자 번역을 체험해보세요!
-
-
-
+ 직접 입력해 실시간 점자 번역을 체험해보세요!
+
@@ -70,23 +52,7 @@ export function Trans() {
}}
value={input}
/>
-
-
-
-
+
-
+
)
}
diff --git a/apps/landing/src/app/normalizeFracBraces.test.ts b/apps/landing/src/app/normalizeFracBraces.test.ts
new file mode 100644
index 00000000..720d452b
--- /dev/null
+++ b/apps/landing/src/app/normalizeFracBraces.test.ts
@@ -0,0 +1,30 @@
+import { expect, test } from 'bun:test'
+
+import { normalizeFracBraces } from './normalizeFracBraces'
+
+test('한 글자 인자를 중괄호로 감싼다', () => {
+ expect(normalizeFracBraces('\\frac34')).toBe('\\frac{3}{4}')
+ expect(normalizeFracBraces('\\frac{3}4')).toBe('\\frac{3}{4}')
+})
+
+test('중첩 분수도 재귀적으로 정규화한다', () => {
+ expect(normalizeFracBraces('\\frac{\\frac12}3')).toBe(
+ '\\frac{\\frac{1}{2}}{3}',
+ )
+})
+
+test('제어 시퀀스 인자를 통째로 감싼다', () => {
+ expect(normalizeFracBraces('\\frac\\pi2')).toBe('\\frac{\\pi}{2}')
+})
+
+test('\\fracture 처럼 접두어가 겹치는 명령은 건드리지 않는다', () => {
+ expect(normalizeFracBraces('\\fracture')).toBe('\\fracture')
+})
+
+test('닫는 중괄호가 없어도 입력을 잃지 않는다', () => {
+ expect(normalizeFracBraces('\\frac{12')).toBe('\\frac{12}{}')
+})
+
+test('분수가 없는 수식은 그대로 둔다', () => {
+ expect(normalizeFracBraces('x^{2}+1')).toBe('x^{2}+1')
+})
diff --git a/apps/landing/src/app/normalizeFracBraces.ts b/apps/landing/src/app/normalizeFracBraces.ts
new file mode 100644
index 00000000..f14f95e2
--- /dev/null
+++ b/apps/landing/src/app/normalizeFracBraces.ts
@@ -0,0 +1,47 @@
+/**
+ * MathLive는 한 글자 인자를 중괄호 없이 직렬화한다 (예: \frac34, \frac{3}4).
+ * braillify의 LaTeX 파서는 \frac{분자}{분모} 형태만 분수로 인식하므로
+ * \frac의 두 인자를 항상 중괄호로 감싼 정규형으로 변환한다.
+ */
+export function normalizeFracBraces(latex: string): string {
+ let out = ''
+ let i = 0
+ while (i < latex.length) {
+ if (latex.startsWith('\\frac', i) && !/[a-zA-Z]/.test(latex[i + 5] ?? '')) {
+ const [num, j] = readArg(latex, i + 5)
+ const [den, k] = readArg(latex, j)
+ out += `\\frac${num}${den}`
+ i = k
+ continue
+ }
+ out += latex[i]
+ i += 1
+ }
+ return out
+}
+
+/** i 위치부터 LaTeX 인자 하나를 읽어 중괄호로 감싼 형태와 다음 인덱스를 돌려준다. */
+function readArg(latex: string, i: number): [string, number] {
+ while (latex[i] === ' ') i += 1
+ if (latex[i] === '{') {
+ let depth = 0
+ let j = i
+ do {
+ if (latex[j] === '{') depth += 1
+ else if (latex[j] === '}') depth -= 1
+ j += 1
+ } while (j < latex.length && depth > 0)
+ // depth === 0 이면 짝이 맞는 '}' 를 j-1 에서 소비한 것이고,
+ // depth > 0 이면 닫는 중괄호 없이 끝난 것이라 내용을 j 까지 살린다.
+ const end = depth === 0 ? j - 1 : j
+ return [`{${normalizeFracBraces(latex.slice(i + 1, end))}}`, j]
+ }
+ if (latex[i] === '\\') {
+ let j = i + 1
+ while (j < latex.length && /[a-zA-Z]/.test(latex[j] ?? '')) j += 1
+ // 제어기호(\, \! 등)는 백슬래시 뒤에 글자가 없으므로 기호 한 글자를 포함시킨다.
+ if (j === i + 1 && j < latex.length) j += 1
+ return [`{${latex.slice(i, j)}}`, j]
+ }
+ return [`{${latex[i] ?? ''}}`, i + 1]
+}
diff --git a/apps/landing/src/app/page.tsx b/apps/landing/src/app/page.tsx
index 6842cea7..16a6bc9c 100644
--- a/apps/landing/src/app/page.tsx
+++ b/apps/landing/src/app/page.tsx
@@ -5,7 +5,7 @@ import PillButton from '@/components/home/PillButton'
import IconDiscord from '@/components/icons/IconDiscord'
import IconKakao from '@/components/icons/IconKakao'
-import { Trans } from './Trans'
+import { DemoTabs } from './DemoTabs'
const SITE_URL = 'https://braillify.kr'
@@ -168,7 +168,7 @@ export default function HomePage() {
-
+
diff --git a/bun.lock b/bun.lock
index 93fe691e..fb78c793 100644
--- a/bun.lock
+++ b/bun.lock
@@ -25,6 +25,7 @@
"braillify": "workspace:*",
"clsx": "^2.1.1",
"katex": "^0.17.0",
+ "mathlive": "^0.110.0",
"next": "16.2.10",
"react": "^19.2.7",
"react-dom": "^19.2.7",
@@ -42,13 +43,15 @@
},
"packages/node": {
"name": "braillify",
- "version": "2.0.1",
+ "version": "2.1.0",
"devDependencies": {
"binaryen": "^130.0.0",
},
},
},
"packages": {
+ "@arnog/colors": ["@arnog/colors@0.5.0", "", {}, "sha512-NB7yqrO7qvInsqJdqz6C6mDU+2oiKmbBbk3czMS0E7KkGxLRy538tEHCsB5TKqmaxxXpi6/U120TnGl8NsDePg=="],
+
"@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="],
"@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="],
@@ -83,6 +86,8 @@
"@babel/types": ["@babel/types@7.29.7", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA=="],
+ "@cortex-js/compute-engine": ["@cortex-js/compute-engine@0.58.0", "", { "dependencies": { "@arnog/colors": "^0.5.0", "complex-esm": "^2.1.1-esm1", "decimal.js": "^10.6.0" } }, "sha512-N0+vXjVZfKwJS7ZIGvq41mojI55m5TrdDXveAXzNjzjZ9iNiNrdEzXL2EmrcP+9GCWCwTonrEeZWAIG78f3INg=="],
+
"@devup-ui/components": ["@devup-ui/components@0.1.47", "", { "dependencies": { "@devup-ui/react": "^1.0.37", "clsx": "^2.1", "react": "^19.2.7" } }, "sha512-B/V2fTbSUIFObF/Zz4gyGhDmuY3vmbej9678494VrmrAM/5JeaN/X+0quWGIpjwPy/rhvAW6nNLEf0XJPZQ7ew=="],
"@devup-ui/eslint-plugin": ["@devup-ui/eslint-plugin@1.0.16", "", { "dependencies": { "@typescript-eslint/utils": "^8.60", "typescript-eslint": "^8.60" } }, "sha512-gXhEVO9c4qGfR6HcCXsnRZHZlepDBZ1BnA0M2pB1/9asXSqWoJmt75xE0beXtt7wgrBHO/Z5gh+iX8Xu3e2ewQ=="],
@@ -417,6 +422,8 @@
"commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
+ "complex-esm": ["complex-esm@2.1.1-esm1", "", {}, "sha512-IShBEWHILB9s7MnfyevqNGxV0A1cfcSnewL/4uPFiSxkcQL4Mm3FxJ0pXMtCXuWLjYz3lRRyk6OfkeDZcjD6nw=="],
+
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="],
@@ -437,6 +444,8 @@
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
+ "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="],
+
"decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "^2.0.0" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="],
"deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="],
@@ -753,6 +762,8 @@
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
+ "mathlive": ["mathlive@0.110.0", "", { "dependencies": { "@cortex-js/compute-engine": "0.58.0" } }, "sha512-UOpJsQ6h1eeN0xZULGTl1MwUB/lZLCDuzKeHvKEh7Zra8U/rtgDNrssj5PZdJtBTIV48AfEhtv6rv47AeMOxJA=="],
+
"mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.3", "", { "dependencies": { "@types/mdast": "^4.0.0", "@types/unist": "^3.0.0", "decode-named-character-reference": "^1.0.0", "devlop": "^1.0.0", "mdast-util-to-string": "^4.0.0", "micromark": "^4.0.0", "micromark-util-decode-numeric-character-reference": "^2.0.0", "micromark-util-decode-string": "^2.0.0", "micromark-util-normalize-identifier": "^2.0.0", "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0", "unist-util-stringify-position": "^4.0.0" } }, "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q=="],
"mdast-util-mdx": ["mdast-util-mdx@3.0.0", "", { "dependencies": { "mdast-util-from-markdown": "^2.0.0", "mdast-util-mdx-expression": "^2.0.0", "mdast-util-mdx-jsx": "^3.0.0", "mdast-util-mdxjs-esm": "^2.0.0", "mdast-util-to-markdown": "^2.0.0" } }, "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w=="],