Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
808 changes: 574 additions & 234 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,26 @@
"@fontsource/poppins": "^5.2.7",
"@jop-software/astro-cookieconsent": "^3.0.1",
"@tailwindcss/vite": "^4.1.17",
"astro": "^5.15.5",
"astro": "^5.16.4",
"astro-icon": "^1.1.5",
"astro-pagefind": "^1.8.5",
"maplibre-gl": "^5.14.0",
"preline": "^3.2.3",
"sass": "^1.94.0",
"sass": "^1.95.0",
"scrollama": "^3.2.0",
"tailwindcss": "^4.1.17",
"vanilla-cookieconsent": "^3.1.0"
},
"devDependencies": {
"@iconify-json/gis": "^1.2.5",
"@iconify-json/mdi": "^1.2.3",
"@typescript-eslint/eslint-plugin": "^8.46.4",
"@typescript-eslint/parser": "^8.46.4",
"@typescript-eslint/eslint-plugin": "^8.49.0",
"@typescript-eslint/parser": "^8.49.0",
"eslint": "^9.39.1",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-astro": "^1.5.0",
"prettier": "^3.6.2",
"prettier": "^3.7.4",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.7.1"
"prettier-plugin-tailwindcss": "^0.7.2"
}
}
23 changes: 23 additions & 0 deletions src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,35 @@ const data = defineCollection({
}),
});

const scroller = defineCollection({
// loader: glob({pattern: '*.json', base: './src/content/scroller'}),
type: 'data',
schema: ({image}) =>
z.array(
z.object({
id: z.string().nonempty().max(100),
title: z.string().nonempty().max(100),
image: image(),
description: z.object({
de: z.string().nonempty(),
en: z.string().nonempty(),
}),
location: z.object({
center: z.array(z.number().finite()).length(2),
zoom: z.number().finite().positive(),
pitch: z.number().int().positive(),
bearing: z.number().int(),
}),
}),
),
});
// 4. Export a single `collections` object to register your collection(s)
export const collections = {
data,
cookies,
posts,
publications,
references,
scroller,
services,
};
131 changes: 131 additions & 0 deletions src/content/scroller/2025.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
[
{
"id": "ai4wildlive",
"title": "AI4WildLIVE Phase II",
"image": "../../images/retrospective/2025/AI4WildLIVE.png",
"description": {
"de": "Wir haben mit der Entwicklung des WildLIVE-GIS in Phase II von AI4WildLIVE begonnen. Ein zentrales Ziel ist die Etablierung eines Analyse-Tools, das das WildLIVE-Portal von Senckenberg mit der Geo Engine verbindet.",
"en": "We started developing the WildLIVE-GIS in Phase II of AI4WildLIVE. A central goal is establishing an analysis tool that connects the Senckenberg WildLIVE portal with the Geo Engine."
},
"location": {
"center": [8.6821, 50.1109],
"zoom": 10,
"pitch": 30,
"bearing": 15
},
"date": "Januar 2025"
},
{
"id": "circular-valley",
"title": "Circular Valley Convention 2025",
"image": "../../images/posts/circular-valley-2025.jpg",
"description": {
"de": "Bei der Circular Valley Convention 2025 haben wir unsere Lösungen für datengetriebene Entscheidungen vorgestellt und diskutiert, wie man Nachhaltigkeit und Effizienz vereinen kann.",
"en": "At the Circular Valley Convention 2025, we presented our solutions for data-driven decisions and discussed how to combine sustainability and efficiency."
},
"location": {
"center": [6.7735, 51.2277],
"zoom": 11,
"pitch": 50,
"bearing": 45
},
"date": "März 2025"
},
{
"id": "ad-astra",
"title": "Ad Astra Summit",
"image": "../../images/retrospective/2025/Ad Astra Summit.jpg",
"description": {
"de": "Beim Ad Astra Summit haben wir gezeigt, wie sich Geodaten effizient für ESG-Reporting und automatisierte Analyseprozesse nutzen lassen. ",
"en": "At the Ad Astra Summit, we demonstrated how geodata can be used efficiently for ESG reporting and automated analysis processes."
},
"location": {
"center": [8.6512, 49.8728],
"zoom": 13,
"pitch": 20,
"bearing": 90
},
"date": "April 2025"
},
{
"id": "living-planet",
"title": "Living Planet Symposium (LPS)",
"image": "../../images/retrospective/2025/Living Planet Symposium.jpg",
"description": {
"de": "Beim Living Planet Symposium (LPS) haben wir unsere neuesten Arbeiten in zwei Vorträgen vorgestellt: zum einen über die deutsche EnMap-Mission und das CropHype-Projekt zur Feldfruchterkennung, zum anderen darüber, wie wir Machine-Learning-Modelle mit der Geo Engine operationalisieren. ",
"en": "At the Living Planet Symposium (LPS), we presented our latest work in two talks: one on the German EnMap mission and the CropHype project for crop detection, and the other on how we operationalize machine learning models with the Geo Engine."
},
"location": {
"center": [16.4138, 48.2163],
"zoom": 14,
"pitch": 60,
"bearing": 120
},
"date": "Juni 2025"
},
{
"id": "baumarten",
"title": "Dominant Tree Types in Germany",
"image": "../../images/posts/dominant-tree-types/image0.png",
"description": {
"de": "Mit der Baumarten-Klassifikation haben wir ein neues Datenprodukt veröffentlicht, das präzise Einblicke in die Waldzusammensetzung in Deutschland bietet.<br><br><a href=\"https://www.geoengine.de/posts/dominant-tree-types/\" target=\"_blank\" rel=\"noopener noreferrer\">Zum Artikel</a>",
"en": "With the tree species classification, we released a new data product offering precise insights into forest composition in Germany.<br><br><a href=\"https://www.geoengine.de/en/posts/dominant-tree-types/\" target=\"_blank\" rel=\"noopener noreferrer\">Read the article</a>"
},
"location": {
"center": [8.7562, 50.809],
"zoom": 12,
"pitch": 35,
"bearing": 75
},
"date": "13. Juni 2025"
},
{
"id": "gfoe-wuerzburg",
"title": "GfÖ-Jahrestagung 2025",
"image": "../../images/retrospective/2025/GfÖ.png",
"description": {
"de": "Bei der GfÖ-Jahrestagung 2025 in Würzburg veranstalteten wir einen Hands-on-Workshop (\"VAT & Geo Engine 4 ML\") zur Kombination von Biodiversitätsdaten mit Fernerkundung und maschinellem Lernen, bei dem wir Machine-Learning-Workflows im Rahmen von NFDI4Biodiversity gezeigt haben.",
"en": "At the GfÖ Annual Meeting 2025 in Würzburg, we hosted a hands-on workshop (\"VAT & Geo Engine 4 ML\") on combining biodiversity data with remote sensing and machine learning, showcasing machine learning workflows within the NFDI4Biodiversity framework."
},
"location": {
"center": [9.9534, 49.7913],
"zoom": 10,
"pitch": 45,
"bearing": 30
},
"date": "September 2025"
},
{
"id": "push-hessen",
"title": "push! Hessen",
"image": "../../images/retrospective/2025/push.png",
"description": {
"de": "Wir haben eine Förderung im push!-Hessen-Programm gewonnen und freuen uns, unsere Lösungen voranzubringen und Unternehmen bei ihren Nachhaltigkeitsberichtspflichten im Bereich Biodiversität zu unterstützen.",
"en": "We won funding in the push! Hessen program and look forward to advancing our solutions and supporting companies with their sustainability reporting obligations in the field of biodiversity."
},
"location": {
"center": [8.2398, 50.0782],
"zoom": 11,
"pitch": 25,
"bearing": 60
},
"date": "September 2025"
},
{
"id": "esa-bic",
"title": "ESA BIC Incubation",
"image": "../../images/posts/esa-bic-2025.png",
"description": {
"de": "Bei ESA BIC haben wir unsere Inkubationszeit erfolgreich abgeschlossen und dadurch neue Bausteine in unserer Infrastruktur geschaffen: eine Random-Forest-Pipeline, einen flexiblen ML-Operator und Modell-Blaupausen.<br><br><a href=\"https://youtu.be/1186CBUKm8Y\" target=\"_blank\" rel=\"noopener noreferrer\">Zum Video</a>",
"en": "We successfully completed our incubation period at ESA BIC, creating new building blocks in our infrastructure: a Random Forest pipeline, a flexible ML operator, and model blueprints.<br><br><a href=\"https://youtu.be/1186CBUKm8Y\" target=\"_blank\" rel=\"noopener noreferrer\">Watch the video</a>"
},
"video": "https://youtu.be/1186CBUKm8Y",
"location": {
"center": [8.6209, 49.8722],
"zoom": 14,
"pitch": 50,
"bearing": 150
},
"date": "15. Oktober 2025"
}
]
2 changes: 2 additions & 0 deletions src/i18n/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export const translations = {
'data.time': 'Zeit',
'data.spatialResolution': 'Räumliche Auflösung',
'data.spatialValidity': 'Räumliche Gültigkeit',
retrospective: 'Retrospektive',
},
en: {
'nav.contact': 'Contact',
Expand Down Expand Up @@ -169,6 +170,7 @@ export const translations = {
'data.time': 'Time',
'data.spatialResolution': 'Spatial Resolution',
'data.spatialValidity': 'Spatial Validity',
retrospective: 'Retrospective',
},
} as const;

Expand Down
Binary file added src/images/retrospective/2025/AI4WildLIVE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/retrospective/2025/GfÖ.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/images/retrospective/2025/push.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 11 additions & 5 deletions src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import {useTranslations} from '../i18n/utils';
interface Props {
title: string;
description?: string;
noNav?: boolean;
noHeader?: boolean;
noFooter?: boolean;
}

const currentLocale = Astro.currentLocale;
const t = useTranslations(currentLocale);

const {title, description = t('header.slogan'), noHeader = false} = Astro.props;
const {title, description = t('header.slogan'), noHeader = false, noFooter = false, noNav = false} = Astro.props;

const pageTitle = `${title} - Geo Engine`;
---
Expand All @@ -31,12 +33,16 @@ const pageTitle = `${title} - Geo Engine`;
</head>

<body>
<NavBar />
{!noNav && <NavBar />}
{!noHeader && <PageHeader>{title}</PageHeader>}
<slot />
<div class="bg-black">
<Footer />
</div>
{
!noFooter && (
<div class="bg-black">
<Footer />
</div>
)
}
<!-- Preline UI -->
<script>
import 'preline/dist/preline.js';
Expand Down
111 changes: 111 additions & 0 deletions src/layouts/Scroller.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
import 'maplibre-gl/dist/maplibre-gl.css';
import '../styles/scroller.css';

import {useTranslations} from '../i18n/utils';
import type {InferEntrySchema} from 'astro:content';

interface Props {
title: string;
description?: string;
chapters: InferEntrySchema<'scroller'>;
}

const currentLocale = Astro.currentLocale;
const t = useTranslations(currentLocale);

const {title, description = t('header.slogan'), chapters} = Astro.props;

if (!chapters) {
throw new Error('Must define `chapters` variable');
}

const pageTitle = `${title} - Geo Engine`;
---

<html lang={currentLocale}>
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
<meta name="viewport" content="width=device-width" />
<meta name="generator" content={Astro.generator} />
<meta name="description" content={description} />
<title>{pageTitle}</title>
</head>

<div id="chapters" data-chapters={JSON.stringify(chapters)}></div>

<script>
import maplibregl from 'maplibre-gl';
import scrollama from 'scrollama';

const div = document.getElementById('chapters');
const property = div?.dataset.chapters;

const chapters = JSON.parse(property ?? '[]');

// --- 1. INITIALIZE MAP ---
const map = new maplibregl.Map({
container: 'map',
style: {
version: 8,
sources: {
'google-satellite': {
type: 'raster',
tiles: ['https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}'],
tileSize: 256,
attribution: '&copy; Google Satellite',
},
},
layers: [{id: 'google-layer', type: 'raster', source: 'google-satellite'}],
},
center: chapters[0].location.center,
zoom: chapters[0].location.zoom,
pitch: chapters[0].location.pitch,
bearing: chapters[0].location.bearing,
interactive: false,
});

// --- 2. SCROLL INTERACTION ---
const scroller = scrollama();

map.on('load', function () {
scroller
.setup({
step: '.step',
offset: 0.5, // Trigger slightly below middle
debug: false,
})
.onStepEnter((response) => {
const chapter = chapters[response.index];

// Highlight active step
document.querySelectorAll('.step').forEach((el) => el.classList.remove('active'));
response.element.classList.add('active');

// Fly to location
map.flyTo({
center: chapter.location.center,
zoom: chapter.location.zoom,
pitch: chapter.location.pitch,
bearing: chapter.location.bearing,
essential: true,
speed: 0.6, // Smooth cinematic speed
curve: 1.2,
});
});
});

window.addEventListener('resize', scroller.resize);
</script>

<body>
<div id="map"></div>

<div id="story">
<slot />
</div>
</body>


</html>
8 changes: 4 additions & 4 deletions src/pages/datenschutzerklaerung.astro
Original file line number Diff line number Diff line change
Expand Up @@ -619,10 +619,10 @@ const cookies = await getCollection('cookies');
stellt, die in der Folge durch uns verarbeitet werden müssen. Die betroffene Person ist beispielsweise verpflichtet uns personenbezogene
Daten bereitzustellen, wenn unser Unternehmen mit ihr einen Vertrag abschließt. Eine Nichtbereitstellung der personenbezogenen
Daten hätte zur Folge, dass der Vertrag mit dem Betroffenen nicht geschlossen werden könnte.<br />
Vor einer Bereitstellung personenbezogener Daten durch den Betroffenen muss sich der Betroffene an einen unserer Mitarbeiter
wenden. Unser Mitarbeiter klärt den Betroffenen einzelfallbezogen darüber auf, ob die Bereitstellung der personenbezogenen Daten
gesetzlich oder vertraglich vorgeschrieben oder für den Vertragsabschluss erforderlich ist, ob eine Verpflichtung besteht, die
personenbezogenen Daten bereitzustellen, und welche Folgen die Nichtbereitstellung der personenbezogenen Daten hätte.
Vor einer Bereitstellung personenbezogener Daten durch den Betroffenen muss sich der Betroffene an einen unserer Mitarbeiter wenden.
Unser Mitarbeiter klärt den Betroffenen einzelfallbezogen darüber auf, ob die Bereitstellung der personenbezogenen Daten gesetzlich
oder vertraglich vorgeschrieben oder für den Vertragsabschluss erforderlich ist, ob eine Verpflichtung besteht, die personenbezogenen
Daten bereitzustellen, und welche Folgen die Nichtbereitstellung der personenbezogenen Daten hätte.
</p>
<h4>Bestehen einer automatisierten Entscheidungsfindung</h4>
<p>Als verantwortungsbewusstes Unternehmen verzichten wir auf eine automatische Entscheidungsfindung oder ein Profiling.</p>
Expand Down
Loading