Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function App() {
}, []);

useEffect(() => {
if (state.fontList && state.fontFamily && state.fontVariant) {
if (state.customFont || (state.fontList && state.fontFamily && state.fontVariant)) {
renderSvg(state).then(result => {
setState(prev => ({ ...prev, ...result }));
});
Expand All @@ -27,6 +27,7 @@ export default function App() {
state.text,
state.size,
state.lineHeight,
state.letterSpacing,
state.union,
state.filled,
state.kerning,
Expand Down
25 changes: 25 additions & 0 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function Sidebar({ state, setState }: SidebarProps) {
text,
size,
lineHeight,
letterSpacing,
union,
kerning,
filled,
Expand Down Expand Up @@ -153,6 +154,30 @@ export default function Sidebar({ state, setState }: SidebarProps) {
/>
</label>

<label>
letter spacing:
<input
type="range"
id="input-letter-spacing"
value={letterSpacing}
onChange={(e) => setState(prev => ({ ...prev, letterSpacing: Number(e.target.value) }))}
min="-50"
max="100"
step="1"
/>
<input
type="number"
value={letterSpacing}
onChange={(e) => {
const value = Math.max(-50, Math.min(100, Number(e.target.value)));
setState(prev => ({ ...prev, letterSpacing: value }));
}}
min="-50"
max="100"
style={{ marginLeft: '8px', width: '60px' }}
/>
</label>

<label>
kerning:
<input
Expand Down
15 changes: 14 additions & 1 deletion src/lib/fontUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export async function loadGoogleFonts() {

export async function renderSvg(state: any) {
try {
const { fontList, fontFamily, fontVariant, customFont, text, size, lineHeight, union, filled, kerning, separate, bezierAccuracy, dxfUnits, fill, stroke, strokeWidth, strokeNonScaling, fillRule } = state;
const { fontList, fontFamily, fontVariant, customFont, text, size, lineHeight, letterSpacing, union, filled, kerning, separate, bezierAccuracy, dxfUnits, fill, stroke, strokeWidth, strokeNonScaling, fillRule } = state;

let font: any;

Expand Down Expand Up @@ -42,6 +42,19 @@ export async function renderSvg(state: any) {
const lineModel = new makerjs.models.Text(font, line, size, union, false, accuracy, { kerning });
const yOffset = -lineIndex * size * lineHeight;

// Apply letter spacing by adjusting each character's origin
if (letterSpacing !== 0) {
let charIndex = 0;
for (const charKey in lineModel.models) {
const charModel = lineModel.models[charKey];
if (charIndex > 0 && charModel.origin) {
// Add to existing origin to preserve kerning (relative additive)
charModel.origin[0] += charIndex * letterSpacing;
}
charIndex++;
}
}

makerjs.model.move(lineModel, [0, yOffset]);
containerModel.models[`line_${lineIndex}`] = lineModel;
});
Expand Down
2 changes: 2 additions & 0 deletions src/store/appStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface AppState {
text: string;
size: number;
lineHeight: number;
letterSpacing: number;
union: boolean;
kerning: boolean;
filled: boolean;
Expand All @@ -32,6 +33,7 @@ export const defaultState: AppState = {
text: 'Verb',
size: 100,
lineHeight: 1.2,
letterSpacing: 0,
union: false,
kerning: true,
filled: false,
Expand Down