Skip to content

Commit a44be8c

Browse files
Add MAIA component with Brain visualization and localization support
1 parent 2c15a7b commit a44be8c

File tree

8 files changed

+247
-0
lines changed

8 files changed

+247
-0
lines changed

public/static/models/Brain.glb

34 MB
Binary file not shown.

src/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,9 @@
468468
"joinedAt": "Joined at",
469469
"addedAt": "Added at",
470470
"jobRestarted": "Job restarted",
471+
"maia-intro-body": "Are you interested in developing your Medical AI application in a collaborative environment with access to state-of-the-art applications and resources? MAIA is a then the right platform for you that provides researchers and students with the tools and infrastructure needed to develop, test, and deploy AI applications in the medical field. Designed to be supported with direct connection to clinical workflows and hospital infrastructures, MAIA offers a unique solution to test your ideas and see them deployed in a real-world clinical setting.",
472+
"maia-intro-footer": "Request your MAIA account today and register a project to start working on your Medical AI solution.",
473+
"maia-intro-header": "Discover ",
471474
"funding-provided-by": "kthcloud is proudly supported by a diverse group of partners. Financial backing is provided by ",
472475
"the": " the ",
473476
"program-and-the": "program and the ",

src/locales/se.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@
464464
"joinedAt": "Gick med",
465465
"addedAt": "Lades till",
466466
"jobRestarted": "Jobb startat om",
467+
"maia": "MAIA",
468+
"maia-text": "BLA BLA BLA",
467469
"funding-provided-by": "kthcloud samarbetar med och stöttas av många organisationer. Finansiellt stöd har vi fått från ",
468470
"the": " ",
469471
"program-and-the": "programmet och ",

src/pages/landing/Landing.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Box, Container } from "@mui/material";
55
import { useKeycloak } from "@react-keycloak/web";
66
import LoadingPage from "../../components/LoadingPage";
77
import Funding from "./components/funding/Funding";
8+
import Maia from "./components/maia/Maia";
89
import { AlertList } from "../../components/AlertList";
910
import { useContext, useEffect } from "react";
1011
import { AuthContextWrapper } from "../../contexts/AuthContextWrapper";
@@ -39,6 +40,7 @@ export function Landing() {
3940
</Container>
4041

4142
<Hero />
43+
<Maia />
4244
<Intro />
4345
<Funding />
4446
</Page>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint-disable react/no-unknown-property */
2+
import { Canvas } from "@react-three/fiber";
3+
import { BrainMesh } from "./BrainMesh";
4+
import * as THREE from "three";
5+
6+
export function Brain({
7+
mobile,
8+
position,
9+
}: {
10+
mobile: boolean;
11+
position: number[];
12+
}) {
13+
return (
14+
<Canvas
15+
style={
16+
mobile
17+
? { height: "250px", width: "100%" }
18+
: {
19+
position: "absolute",
20+
top: "0",
21+
left: "0",
22+
height: "100%",
23+
width: "100%",
24+
}
25+
}
26+
>
27+
<ambientLight intensity={0.5} />
28+
<directionalLight position={[5, 5, 5]} intensity={2} color={"#fffecc"} />
29+
<directionalLight position={[5, -5, 5]} intensity={1} color={"#faa"} />
30+
<directionalLight position={[-5, 5, 5]} intensity={1} color={"#aaf"} />
31+
32+
<BrainMesh
33+
mobile={mobile}
34+
position={position}
35+
props={{
36+
material: new THREE.MeshBasicMaterial({
37+
color: "yellow",
38+
}),
39+
}}
40+
/>
41+
</Canvas>
42+
);
43+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// @ts-nocheck
2+
3+
import { useRef, useEffect, useState } from "react";
4+
import { useFrame, useLoader } from "@react-three/fiber";
5+
import { GLTFLoader } from "three-stdlib";
6+
import { Vector3 } from "three";
7+
8+
const url = "/static/models/Brain.glb";
9+
10+
function BrainModel() {
11+
const gltf = useLoader(GLTFLoader, url);
12+
gltf.scene.traverse((child) => {
13+
if (child.material) child.material.metalness = 0;
14+
});
15+
16+
return <primitive object={gltf.scene}></primitive>;
17+
}
18+
19+
export function BrainMesh({ mobile, position, props }) {
20+
const [mouseCoordinates, setMouseCoordinates] = useState({ x: 0, y: 0 });
21+
const meshRef = useRef();
22+
23+
const mouseMoveHandler = (event) => {
24+
setMouseCoordinates({
25+
x: event.clientX,
26+
y: event.clientY,
27+
});
28+
};
29+
30+
useEffect(() => {
31+
window.addEventListener("mousemove", mouseMoveHandler);
32+
return () => {
33+
window.removeEventListener("mousemove", mouseMoveHandler);
34+
};
35+
}, []);
36+
37+
useFrame(({ camera }, delta) => {
38+
if (mobile) {
39+
meshRef.current.rotation.y += delta;
40+
} else {
41+
let x = mouseCoordinates.x / window.innerWidth;
42+
let y = 1 - mouseCoordinates.y / window.innerHeight;
43+
const vector = new Vector3(x, y, 0);
44+
vector.unproject(camera);
45+
meshRef.current.rotation.set(1 - vector.y - 0.8, vector.x, 0);
46+
}
47+
});
48+
49+
return (
50+
<mesh position={position} scale={0.03} ref={meshRef} {...props}>
51+
<BrainModel />
52+
</mesh>
53+
);
54+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import {
2+
Grid,
3+
Card,
4+
Container,
5+
Typography,
6+
Button,
7+
Stack,
8+
Box,
9+
} from "@mui/material";
10+
import "./intro.css";
11+
import { Brain } from "./Brain";
12+
import { useTranslation } from "react-i18next";
13+
import { Link } from "react-router-dom";
14+
15+
const Maia = () => {
16+
const { t } = useTranslation();
17+
18+
return (
19+
<Box component="div" sx={{ overflow: "hidden", marginBottom: 5 }}>
20+
<Container maxWidth="lg">
21+
<Card sx={{ boxShadow: 20, background: "#242424ff", color: "#ffffff" }}>
22+
<Grid
23+
container
24+
justifyContent="center"
25+
alignItems="center"
26+
rowSpacing={4}
27+
sx={{
28+
padding: {
29+
xs: "50px 16px",
30+
sm: "50px 58px",
31+
md: "50px 50px 50px 50px",
32+
},
33+
}}
34+
>
35+
{/* Text block - comes first on all screen sizes */}
36+
<Grid item xs={12} md={5} order={{ xs: 1, md: 1 }}>
37+
<Typography
38+
variant="h2"
39+
sx={{
40+
fontWeight: "400",
41+
marginBottom: "40px",
42+
textAlign: { xs: "center", md: "left" },
43+
}}
44+
>
45+
{t("maia-intro-header")} <strong>MAIA</strong>
46+
</Typography>
47+
48+
<Typography variant="subtitle1" sx={{ marginBottom: "40px" }}>
49+
{t("maia-intro-body")}
50+
</Typography>
51+
<Stack direction="row" spacing={2}>
52+
<Typography variant="subtitle2" sx={{ marginBottom: "40px" }}>
53+
{t("maia-intro-footer")}
54+
</Typography>
55+
56+
<Button
57+
variant="contained"
58+
sx={{ whiteSpace: "nowrap", px: 4 }}
59+
component={Link}
60+
to="https://maia.app.cloud.cbh.kth.se/maia/register"
61+
>
62+
{t("button-get-started")}
63+
</Button>
64+
</Stack>
65+
</Grid>
66+
67+
{/* Brain block - comes second on desktop, second (below) on mobile */}
68+
<Grid item xs={12} md={7} order={{ xs: 2, md: 2 }}>
69+
{/* Desktop brain */}
70+
<Box
71+
component="div"
72+
sx={{
73+
display: { xs: "none", sm: "none", md: "block" },
74+
textAlign: "right",
75+
}}
76+
>
77+
<Brain position={[3, 0, 0]} mobile={false} />
78+
</Box>
79+
80+
{/* Mobile brain */}
81+
<Box
82+
component="div"
83+
sx={{
84+
display: { xs: "block", sm: "block", md: "none" },
85+
padding: 0,
86+
textAlign: "center",
87+
}}
88+
>
89+
<Brain mobile position={[0, 0, 0]} />
90+
</Box>
91+
</Grid>
92+
</Grid>
93+
</Card>
94+
</Container>
95+
</Box>
96+
97+
);
98+
};
99+
100+
export default Maia;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
.lil-curve {
2+
width: 64px;
3+
text-align: center;
4+
}
5+
.jeremy-card {
6+
z-index: 10;
7+
}
8+
.blur {
9+
position: relative;
10+
top: 100px;
11+
left: -150px;
12+
z-index: 1;
13+
margin-top: -100px;
14+
width: 500px;
15+
}
16+
17+
@media screen and (min-width: 900px) {
18+
.lil-curve {
19+
transform: translateY(-100px);
20+
}
21+
}
22+
@media screen and (max-width: 900px) {
23+
.blur {
24+
position: relative;
25+
top: 0px;
26+
left: -10px;
27+
margin: 0 auto;
28+
margin-top: -100px;
29+
margin-bottom: -30px;
30+
31+
text-align: center;
32+
}
33+
}
34+
35+
@media screen and (max-width: 600px) {
36+
.blur {
37+
top: 0px;
38+
left: -500px;
39+
margin-bottom: -30px;
40+
41+
text-align: center;
42+
}
43+
}

0 commit comments

Comments
 (0)