Merge pull request 'ui/3d-fonts: replace troika with 3d rendered default font' (#5091) from ui/password-input-reveal into main

Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5091
This commit is contained in:
hsjobeki
2025-09-03 19:38:05 +00:00
4 changed files with 56 additions and 31 deletions

View File

@@ -91,6 +91,8 @@ mkShell {
pushd "$CLAN_CORE_PATH/pkgs/clan-app/ui"
export NODE_PATH="$(pwd)/node_modules"
export PATH="$NODE_PATH/.bin:$(pwd)/bin:$PATH"
rm -rf .fonts || true
cp -r ${self'.packages.fonts} .fonts
chmod -R +w .fonts
mkdir -p api

View File

@@ -151,10 +151,12 @@ export const ServiceRoute = (props: {
color="primary"
inverted
>
{props.id}
{props.label}
</Typography>
<Icon icon="Code" size="0.75rem" inverted color="tertiary" />
</div>
<div class="flex w-full flex-row items-center gap-1">
{/* Same subtitle as Machine */}
{/* <div class="flex w-full flex-row items-center gap-1">
<Icon icon="Code" size="0.75rem" inverted color="tertiary" />
<Typography
hierarchy="label"
@@ -165,7 +167,7 @@ export const ServiceRoute = (props: {
>
{props.instance.resolved.usage_ref.name}
</Typography>
</div>
</div> */}
</div>
</A>
);
@@ -181,8 +183,8 @@ const Services = () => {
return [];
}
return Object.entries(ctx.serviceInstancesQuery.data).map(
([id, instance]) => {
return Object.entries(ctx.serviceInstancesQuery.data)
.map(([id, instance]) => {
const moduleName = instance.module.name;
const label = moduleName == id ? moduleName : `${moduleName} (${id})`;
@@ -191,8 +193,8 @@ const Services = () => {
label,
instance: instance,
};
},
);
})
.sort((a, b) => a.label.localeCompare(b.label));
};
return (

View File

@@ -18,8 +18,8 @@ export const SectionServices = () => {
return [];
}
return (ctx.machinesQuery.data[machineName].instance_refs ?? []).map(
(id) => {
return (ctx.machinesQuery.data[machineName].instance_refs ?? [])
.map((id) => {
const instance = ctx.serviceInstancesQuery.data?.[id];
if (!instance) {
throw new Error(`Service instance ${id} not found`);
@@ -31,8 +31,8 @@ export const SectionServices = () => {
instance,
label: module.name == id ? module.name : `${module.name} (${id})`,
};
},
);
})
.sort((a, b) => a.label.localeCompare(b.label));
};
return (

View File

@@ -2,9 +2,9 @@ import * as THREE from "three";
import { ObjectRegistry } from "./ObjectRegistry";
import { Accessor, createEffect, createRoot, on } from "solid-js";
import { renderLoop } from "./RenderLoop";
// @ts-expect-error: No types for troika-three-text
import { Text } from "troika-three-text";
import ttf from "../../.fonts/ArchivoSemiCondensed-Medium.ttf";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry.js";
import { FontLoader } from "three/examples/jsm/Addons";
import jsonfont from "three/examples/fonts/helvetiker_regular.typeface.json";
// Constants
const BASE_SIZE = 0.9;
@@ -201,26 +201,49 @@ export class MachineRepr {
private createLabel(id: string) {
const group = new THREE.Group();
// 0x162324
const text = new Text();
text.text = id;
text.font = ttf;
text.fontSize = 0.1;
text.color = 0xffffff;
text.anchorX = "center";
text.anchorY = "middle";
text.position.set(0, 0, 0.01);
text.outlineWidth = 0.005;
text.outlineColor = 0x162324;
// const text = new Text();
// text.text = id;
// text.font = ttf;
// text.fontSize = 0.1;
// text.color = 0xffffff;
// text.anchorX = "center";
// text.anchorY = "middle";
// text.position.set(0, 0, 0.01);
// text.outlineWidth = 0.005;
// text.outlineColor = 0x162324;
// text.sync(() => {
// renderLoop.requestRender();
// });
// Re-render on text changes
text.sync(() => {
renderLoop.requestRender();
const textMaterial = new THREE.MeshPhongMaterial({
color: 0xffffff,
});
const textGeo = new TextGeometry(id, {
font: new FontLoader().parse(jsonfont),
size: 0.09,
depth: 0.001,
curveSegments: 12,
bevelEnabled: false,
});
const text = new THREE.Mesh(textGeo, textMaterial);
textGeo.computeBoundingBox();
const bbox = textGeo.boundingBox;
if (bbox) {
const xMid = -0.5 * (bbox.max.x - bbox.min.x);
// const yMid = -0.5 * (bbox.max.y - bbox.min.y);
// const zMid = -0.5 * (bbox.max.z - bbox.min.z);
// Translate geometry so center is at origin / baseline aligned with y=0
textGeo.translate(xMid, -0.035, 0);
}
// --- Background (rounded rect) ---
const padding = 0.04;
// TODO: compute from text.bounds after sync
const bgWidth = text.text.length * 0.07 + padding;
const textWidth = bbox ? bbox.max.x - bbox.min.x : 1;
const bgWidth = textWidth + 10 * padding;
// const bgWidth = text.text.length * 0.07 + padding;
const bgHeight = 0.1 + 2 * padding;
const radius = 0.02;
@@ -230,8 +253,6 @@ export class MachineRepr {
const bg = new THREE.Mesh(bgGeom, bgMat);
bg.position.set(0, 0, -0.01);
// bg.position.set(0, 0, -0.01); // slightly behind text
// --- Arrow (triangle pointing down) ---
const arrowShape = new THREE.Shape();
arrowShape.moveTo(-0.05, 0);