diff --git a/apps/pyconkr-2026/src/assets/fonts/dosgothic.woff b/apps/pyconkr-2026/src/assets/fonts/dosgothic.woff
new file mode 100644
index 00000000..86f75a7a
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dosgothic.woff differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/dosmyungjo.woff b/apps/pyconkr-2026/src/assets/fonts/dosmyungjo.woff
new file mode 100644
index 00000000..343fa4f7
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dosmyungjo.woff differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/dossaemmul.woff b/apps/pyconkr-2026/src/assets/fonts/dossaemmul.woff
new file mode 100644
index 00000000..97739f07
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dossaemmul.woff differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/dunggeunmo.woff b/apps/pyconkr-2026/src/assets/fonts/dunggeunmo.woff
new file mode 100644
index 00000000..6e007036
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/dunggeunmo.woff differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/exqt_wide12.ttf b/apps/pyconkr-2026/src/assets/fonts/exqt_wide12.ttf
new file mode 100644
index 00000000..d030de90
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/exqt_wide12.ttf differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/exqt_wide135.ttf b/apps/pyconkr-2026/src/assets/fonts/exqt_wide135.ttf
new file mode 100644
index 00000000..8ac13c8c
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/exqt_wide135.ttf differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/exqt_wide15.ttf b/apps/pyconkr-2026/src/assets/fonts/exqt_wide15.ttf
new file mode 100644
index 00000000..51421800
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/exqt_wide15.ttf differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri-mono11.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri-mono11.woff2
new file mode 100644
index 00000000..ff325bb7
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri-mono11.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri11-condensed.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri11-condensed.woff2
new file mode 100644
index 00000000..fd0b1c57
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri11-condensed.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri11.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri11.woff2
new file mode 100644
index 00000000..659863b5
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri11.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri14.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri14.woff2
new file mode 100644
index 00000000..d6cdf5dc
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri14.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/galmuri9.woff2 b/apps/pyconkr-2026/src/assets/fonts/galmuri9.woff2
new file mode 100644
index 00000000..336a89c3
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/galmuri9.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/maruminya.woff2 b/apps/pyconkr-2026/src/assets/fonts/maruminya.woff2
new file mode 100644
index 00000000..80cb96a3
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/maruminya.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/mulmaru.woff2 b/apps/pyconkr-2026/src/assets/fonts/mulmaru.woff2
new file mode 100644
index 00000000..6ecfe354
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/mulmaru.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/neodgm.woff2 b/apps/pyconkr-2026/src/assets/fonts/neodgm.woff2
new file mode 100644
index 00000000..efc5cc44
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/neodgm.woff2 differ
diff --git a/apps/pyconkr-2026/src/assets/fonts/pfstardust.woff2 b/apps/pyconkr-2026/src/assets/fonts/pfstardust.woff2
new file mode 100644
index 00000000..d832bf1b
Binary files /dev/null and b/apps/pyconkr-2026/src/assets/fonts/pfstardust.woff2 differ
diff --git a/apps/pyconkr-2026/src/components/FontSwitcher.tsx b/apps/pyconkr-2026/src/components/FontSwitcher.tsx
new file mode 100644
index 00000000..333f3e82
--- /dev/null
+++ b/apps/pyconkr-2026/src/components/FontSwitcher.tsx
@@ -0,0 +1,126 @@
+import { FC, useState } from "react";
+
+/**
+ * 가독성 비교용 임시 폰트 전환 도구.
+ * 페이지 최상단에 고정된 select 로 폰트를 바꾸면 --app-font(전역 CSS 변수)를 덮어써
+ * 본문(MDX/네이티브 HTML)과 MUI Typography 가 한 번에 전환된다.
+ * (각 폰트 정의는 main.css 의 @font-face, 기본값은 globalStyles 의 :root 참고)
+ */
+const FALLBACK = `"Pretendard", -apple-system, BlinkMacSystemFont, system-ui, "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", sans-serif`;
+
+const FONT_OPTIONS: { label: string; stack: string }[] = [
+ // 기본값(:root --app-font)과 동일한 exqt 스택
+ {
+ label: "exqt (현재 기본)",
+ stack: `"exqtEnglish", "exqtNumber", "exqt", ${FALLBACK}`,
+ },
+ {
+ label: "exqt 가로 1.2배",
+ stack: `"exqtWide12", ${FALLBACK}`,
+ },
+ {
+ label: "exqt 가로 1.35배",
+ stack: `"exqtWide135", ${FALLBACK}`,
+ },
+ {
+ label: "exqt 가로 1.5배",
+ stack: `"exqtWide15", ${FALLBACK}`,
+ },
+ {
+ label: "둥근모꼴+Fixedsys",
+ stack: `"RoundedFixedsys", ${FALLBACK}`,
+ },
+ {
+ label: "PF스타더스트",
+ stack: `"PFStardust", ${FALLBACK}`,
+ },
+ {
+ label: "갈무리11 (닌텐도DS풍)",
+ stack: `"Galmuri11", ${FALLBACK}`,
+ },
+ {
+ label: "갈무리14 (큰 크기)",
+ stack: `"Galmuri14", ${FALLBACK}`,
+ },
+ {
+ label: "갈무리9 (작은 크기)",
+ stack: `"Galmuri9", ${FALLBACK}`,
+ },
+ {
+ label: "Neo둥근모",
+ stack: `"NeoDunggeunmo", ${FALLBACK}`,
+ },
+ {
+ label: "물마루",
+ stack: `"Mulmaru", ${FALLBACK}`,
+ },
+ {
+ label: "마루민야 (둥근고딕)",
+ stack: `"MaruMinya", ${FALLBACK}`,
+ },
+ {
+ label: "갈무리Mono11 (고정폭)",
+ stack: `"GalmuriMono11", ${FALLBACK}`,
+ },
+ {
+ label: "갈무리11 Condensed (좁게)",
+ stack: `"Galmuri11Condensed", ${FALLBACK}`,
+ },
+ {
+ label: "DOS고딕",
+ stack: `"DOSGothic", ${FALLBACK}`,
+ },
+ {
+ label: "DOS샘물",
+ stack: `"DOSSaemmul", ${FALLBACK}`,
+ },
+ {
+ label: "DOS명조 (픽셀 명조)",
+ stack: `"DOSMyungjo", ${FALLBACK}`,
+ },
+ {
+ label: "Pretendard (비교용)",
+ stack: FALLBACK,
+ },
+];
+
+export const FontSwitcher: FC = () => {
+ const [index, setIndex] = useState(0);
+
+ return (
+
+ );
+};
diff --git a/apps/pyconkr-2026/src/main.css b/apps/pyconkr-2026/src/main.css
index 57923f13..12c035e8 100644
--- a/apps/pyconkr-2026/src/main.css
+++ b/apps/pyconkr-2026/src/main.css
@@ -16,3 +16,98 @@
unicode-range: U+0030-0039; /* 숫자 */
size-adjust: 120%;
}
+
+/* exqt 가로 확장본 (글리프를 x축으로만 늘려 ㅏㅓㅑㅕ 곁가지가 길어지도록 재생성. 세로/행간 불변) */
+@font-face {
+ font-family: "exqtWide12";
+ src: url("assets/fonts/exqt_wide12.ttf") format("truetype");
+}
+
+@font-face {
+ font-family: "exqtWide135";
+ src: url("assets/fonts/exqt_wide135.ttf") format("truetype");
+}
+
+@font-face {
+ font-family: "exqtWide15";
+ src: url("assets/fonts/exqt_wide15.ttf") format("truetype");
+}
+
+/* 가독성 비교용 후보 폰트들 (상단 FontSwitcher select에서 전환) */
+@font-face {
+ font-family: "RoundedFixedsys"; /* 둥근모꼴+Fixedsys, https://noonnu.cc/font_page/250 */
+ src: url("assets/fonts/dunggeunmo.woff") format("woff");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "PFStardust"; /* PF스타더스트 3.0, https://noonnu.cc/font_page/1614 */
+ src: url("assets/fonts/pfstardust.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "Galmuri9"; /* 갈무리9 (OFL), https://galmuri.quiple.dev */
+ src: url("assets/fonts/galmuri9.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "Galmuri11"; /* 갈무리11 (OFL, 닌텐도DS 스타일) */
+ src: url("assets/fonts/galmuri11.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "Galmuri14"; /* 갈무리14 (OFL, 큰 크기) */
+ src: url("assets/fonts/galmuri14.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "NeoDunggeunmo"; /* Neo둥근모 (OFL), https://github.com/neodgm/neodgm */
+ src: url("assets/fonts/neodgm.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "Mulmaru"; /* 물마루 (OFL), https://github.com/mushsooni/mulmaru */
+ src: url("assets/fonts/mulmaru.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "GalmuriMono11"; /* 갈무리Mono11 (OFL, 고정폭) */
+ src: url("assets/fonts/galmuri-mono11.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "Galmuri11Condensed"; /* 갈무리11 Condensed (OFL, 좁은 폭) */
+ src: url("assets/fonts/galmuri11-condensed.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "MaruMinya"; /* 마루민야 x12y12 (OFL), https://github.com/quiple/x12y12pxMaruMinyaHangul */
+ src: url("assets/fonts/maruminya.woff2") format("woff2");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "DOSGothic"; /* DOS고딕 (MIT), https://noonnu.cc/font_page/239 */
+ src: url("assets/fonts/dosgothic.woff") format("woff");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "DOSSaemmul"; /* DOS샘물 (MIT), https://noonnu.cc/font_page/240 */
+ src: url("assets/fonts/dossaemmul.woff") format("woff");
+ font-display: swap;
+}
+
+@font-face {
+ font-family: "DOSMyungjo"; /* DOS명조 (MIT, 픽셀 명조), https://noonnu.cc/font_page/238 */
+ src: url("assets/fonts/dosmyungjo.woff") format("woff");
+ font-display: swap;
+}
diff --git a/apps/pyconkr-2026/src/main.tsx b/apps/pyconkr-2026/src/main.tsx
index 1050e5ee..8d0a0a51 100644
--- a/apps/pyconkr-2026/src/main.tsx
+++ b/apps/pyconkr-2026/src/main.tsx
@@ -14,6 +14,7 @@ import { createRoot } from "react-dom/client";
import { RouterProvider } from "react-router-dom";
import "./main.css";
+import { FontSwitcher } from "./components/FontSwitcher.tsx";
import { IS_DEBUG_ENV } from "./consts";
import { LOCAL_STORAGE_LANGUAGE_KEY } from "./consts/local_stroage.ts";
import { PyConKRMDXComponents } from "./consts/mdx_components.ts";
@@ -98,6 +99,7 @@ export const MainApp: FC = () => {
+
diff --git a/apps/pyconkr-2026/src/styles/globalStyles.ts b/apps/pyconkr-2026/src/styles/globalStyles.ts
index 54067734..9b7a3e83 100644
--- a/apps/pyconkr-2026/src/styles/globalStyles.ts
+++ b/apps/pyconkr-2026/src/styles/globalStyles.ts
@@ -3,8 +3,13 @@ import { createTheme } from "@mui/material/styles";
export const muiTheme = createTheme({
typography: {
- fontFamily:
- 'exqtEnglish, exqtNumber, exqt, Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif',
+ // 실제 폰트 스택은 CSS 변수 --app-font 로 주입(상단 FontSwitcher select에서 전환). 기본값은 :root 에 정의.
+ fontFamily: "var(--app-font)",
+ // exqt 폰트의 자간이 좁아 가독성이 떨어지므로 모든 Typography variant의 자간을 통일해 넓힘.
+ // (line-height는 variant별 기본값을 유지하기 위해 의도적으로 지정하지 않음)
+ allVariants: {
+ letterSpacing: "0.04em",
+ },
},
palette: {
mode: "dark",
@@ -126,30 +131,23 @@ export const muiTheme = createTheme({
export const globalStyles = css`
@import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard/dist/web/static/pretendard.css");
+ /* 기본 폰트 스택. FontSwitcher select가 document.documentElement 의 --app-font 를 덮어써 전환한다. */
+ :root {
+ --app-font:
+ "exqtEnglish", "exqtNumber", "exqt", "Pretendard", -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI",
+ "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;
+ }
+
html,
body {
- font-family:
- "exqtEnglish",
- "exqtNumber",
- "exqt",
- "Pretendard",
- -apple-system,
- BlinkMacSystemFont,
- system-ui,
- Roboto,
- "Helvetica Neue",
- "Segoe UI",
- "Apple SD Gothic Neo",
- "Noto Sans KR",
- "Malgun Gothic",
- "Apple Color Emoji",
- "Segoe UI Emoji",
- "Segoe UI Symbol",
- sans-serif;
+ font-family: var(--app-font);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-touch-callout: none;
+ letter-spacing: 0.04em;
+ line-height: 1.7;
+
overscroll-behavior: none;
word-break: keep-all;
overflow-wrap: break-all;
diff --git a/dotenv/.env.development b/dotenv/.env.development
index aebb10a0..5df0335d 100644
--- a/dotenv/.env.development
+++ b/dotenv/.env.development
@@ -1,7 +1,7 @@
-VITE_PYCONKR_FRONTEND_DOMAIN=https://dev.pycon.kr
-VITE_PYCONKR_BACKEND_API_DOMAIN=https://rest-api-dev.pycon.kr
-VITE_PYCONKR_ACCOUNTS_DOMAIN=https://accounts-dev.pycon.kr
-VITE_PYCONKR_BACKEND_CSRF_COOKIE_NAME=DEBUG_PYCONKR_BACKEND_csrftoken
-VITE_PYCONKR_BACKEND_SESSION_COOKIE_NAME=DEBUG_PYCONKR_BACKEND_sessionid
-VITE_PYCONKR_SHOP_IMP_ACCOUNT_ID=imp80859147
+VITE_PYCONKR_FRONTEND_DOMAIN=https://2026.pycon.kr
+VITE_PYCONKR_BACKEND_API_DOMAIN=https://rest-api.pycon.kr
+VITE_PYCONKR_ACCOUNTS_DOMAIN=https://accounts.pycon.kr
+VITE_PYCONKR_BACKEND_CSRF_COOKIE_NAME=PYCONKR_BACKEND_csrftoken
+VITE_PYCONKR_BACKEND_SESSION_COOKIE_NAME=PYCONKR_BACKEND_sessionid
+VITE_PYCONKR_SHOP_IMP_ACCOUNT_ID=imp96676915
VITE_FARO_COLLECTOR_URL=https://faro.mudev.cc/collect