From 357ac871bf4bca10de86b762eecd45cb6423c0f9 Mon Sep 17 00:00:00 2001
From: tezc4t
Date: Sun, 28 Jun 2026 16:51:45 +0200
Subject: [PATCH] 3ds inte.
---
.github/workflows/electron-build.yml | 4 +-
.vscode/tasks.json | 40 ++
3ds-build.yml | 37 ++
3ds/Makefile | 32 ++
3ds/banner.png | Bin 0 -> 8990 bytes
3ds/icon.png | Bin 0 -> 6898 bytes
3ds/include/main.h | 0
3ds/romfs/admin.php | 109 +++++
3ds/romfs/api.php | 82 ++++
3ds/romfs/contact.php | 88 ++++
3ds/romfs/index.html | 397 ++++++++++++++++++
3ds/romfs/main.js | 401 ++++++++++++++++++
3ds/romfs/style.css | 593 +++++++++++++++++++++++++++
3ds/source/main.cpp | 92 +++++
c_cpp_properties.json | 20 +
15 files changed, 1893 insertions(+), 2 deletions(-)
create mode 100644 .vscode/tasks.json
create mode 100644 3ds-build.yml
create mode 100644 3ds/Makefile
create mode 100644 3ds/banner.png
create mode 100644 3ds/icon.png
create mode 100644 3ds/include/main.h
create mode 100644 3ds/romfs/admin.php
create mode 100644 3ds/romfs/api.php
create mode 100644 3ds/romfs/contact.php
create mode 100644 3ds/romfs/index.html
create mode 100644 3ds/romfs/main.js
create mode 100644 3ds/romfs/style.css
create mode 100644 3ds/source/main.cpp
create mode 100644 c_cpp_properties.json
diff --git a/.github/workflows/electron-build.yml b/.github/workflows/electron-build.yml
index abe6845..40429c8 100644
--- a/.github/workflows/electron-build.yml
+++ b/.github/workflows/electron-build.yml
@@ -19,8 +19,8 @@ jobs:
with:
node-version: '22'
- - name: Installation des dépendances
- run: npm install
+ - name: Install dependencies
+ run: npm ci
- name: Build de l'application (Windows)
run: npm run build
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..a97b36c
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,40 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "3DS: Build CIA (Docker)",
+ "type": "shell",
+ "command": "docker run --rm -v \"${workspaceFolder}:/project\" -w /project/3ds devkitpro/devkitarm:latest bash -c 'source /etc/profile.d/devkit-env.sh && make cia'",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "problemMatcher": [],
+ "presentation": {
+ "echo": true,
+ "reveal": "always",
+ "focus": false,
+ "panel": "shared",
+ "showReuseMessage": true,
+ "clear": false
+ },
+ "detail": "Compile le projet 3DS en .cia en utilisant l'image Docker de devkitPro."
+ },
+ {
+ "label": "3DS: Clean Build (Docker)",
+ "type": "shell",
+ "command": "docker run --rm -v \"${workspaceFolder}:/project\" -w /project/3ds devkitpro/devkitarm:latest bash -c 'source /etc/profile.d/devkit-env.sh && make clean'",
+ "group": "build",
+ "problemMatcher": [],
+ "presentation": {
+ "echo": true,
+ "reveal": "always",
+ "focus": false,
+ "panel": "shared",
+ "showReuseMessage": true,
+ "clear": true
+ },
+ "detail": "Nettoie les fichiers de build du projet 3DS."
+ }
+ ]
+}
diff --git a/3ds-build.yml b/3ds-build.yml
new file mode 100644
index 0000000..115e067
--- /dev/null
+++ b/3ds-build.yml
@@ -0,0 +1,37 @@
+name: Build 3DS App (CIA)
+
+on:
+ push:
+ branches:
+ - "AppPhoneAPK&IPA" # Déclenché sur la même branche que les autres builds
+ paths:
+ - '3ds/**' # Uniquement si des fichiers dans 3ds/ sont modifiés
+ - 'SRC/**' # Ou si les sources web sont modifiées
+ workflow_dispatch:
+
+jobs:
+ build-3ds:
+ runs-on: ubuntu-latest
+ container: devkitpro/devkitarm:latest
+
+ steps:
+ - name: Checkout du code
+ uses: actions/checkout@v4
+
+ - name: Préparation des fichiers RomFS
+ run: |
+ echo "Copie des fichiers web vers le dossier romfs..."
+ mkdir -p 3ds/romfs
+ cp -r SRC/* 3ds/romfs/
+
+ - name: Compilation de l'application 3DS
+ working-directory: ./3ds
+ run: |
+ echo "Lancement du build 3DS via make..."
+ make cia
+
+ - name: Upload de l'artefact CIA
+ uses: actions/upload-artifact@v4
+ with:
+ name: OpenPlanetsMaps-3DS-CIA
+ path: 3ds/OpenPlanetsMaps.cia
\ No newline at end of file
diff --git a/3ds/Makefile b/3ds/Makefile
new file mode 100644
index 0000000..f3917c8
--- /dev/null
+++ b/3ds/Makefile
@@ -0,0 +1,32 @@
+# 3ds/Makefile
+
+# --- Configuration du Projet ---
+TARGET := OpenPlanetsMaps_3DS # Nom du .elf, .3dsx, .smdh
+CIA_TARGET := OpenPlanetsMaps.cia # Nom du fichier .cia final
+NAME := OpenPlanetsMaps
+AUTHOR := Tezca
+DESCRIPTION := Visionneur de données astronomiques
+
+# --- Fichiers et Dossiers ---
+SOURCES := source
+DATA := romfs
+INCLUDES := include
+
+# --- Options de compilation ---
+CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++17
+
+# --- Bibliothèques ---
+# Ajoutez des bibliothèques ici si nécessaire (ex: -lcitro2d)
+LIBS := -lcitro2d -lctru -lm
+
+# Variables d'environnement devkitPro
+ifeq ($(strip $(DEVKITPRO)),)
+$(error "Veuillez définir la variable d'environnement DEVKITPRO.")
+endif
+
+# --- Système de Build (ne pas modifier) ---
+include $(DEVKITPRO)/lib/dkp-rules/dkp.mk
+
+# --- Cibles de Build ---
+# Les cibles 'all', 'cia', et 'clean' sont gérées automatiquement par dkp.mk
+# Il n'est plus nécessaire de les définir manuellement.
diff --git a/3ds/banner.png b/3ds/banner.png
new file mode 100644
index 0000000000000000000000000000000000000000..4a49e54e1dcec2742a8725d3bd313baf428e11e1
GIT binary patch
literal 8990
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
QhWG}cB&RA{DQy<|Ki-#N$p8QV
literal 0
HcmV?d00001
diff --git a/3ds/icon.png b/3ds/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..8261348717ee2e9589336232bc9a4e02b61512a1
GIT binary patch
literal 6898
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 "SET NAMES utf8", PDO::ATTR_EMULATE_PREPARES => false];
+ $pdo = new PDO("mysql:host=$host;port=3306;dbname=$dbname;charset=utf8;protocol=tcp", $db_user, $db_pass, $options);
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $planete = $_POST['planete'];
+ $nom = $_POST['nom'];
+ $date = $_POST['date'];
+ $url = $_POST['url'];
+ $description = $_POST['description'];
+
+ $allowedTables = [
+ 'mercury' => 'MERCURY', 'venus' => 'VENUS', 'earth' => 'EARTH',
+ 'mars' => 'MARS', 'jupiter' => 'JUPITER', 'saturn' => 'SATURN',
+ 'uranus' => 'URANUS', 'neptune' => 'NEPTUNE'
+ ];
+
+ if (array_key_exists($planete, $allowedTables)) {
+ $nomTable = $allowedTables[$planete];
+ $stmt = $pdo->prepare("INSERT INTO $nomTable (title, date, url, explanation) VALUES (?, ?, ?, ?)");
+ $stmt->execute([$nom, $date, $url, $description]);
+
+ $message = "Row successfully added to the $nomTable table!
";
+ }
+ } catch (PDOException $e) {
+ $message = "SQL Error: " . $e->getMessage() . "
";
+ }
+}
+?>
+
+
+
+
+ Admin Panel - OpenPlanetsMaps
+
+
+
+
+
+
+
Admin Login
+
= $error ?>
+
+
+
+
Add a row
+ = $message ?>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3ds/romfs/api.php b/3ds/romfs/api.php
new file mode 100644
index 0000000..300dbc1
--- /dev/null
+++ b/3ds/romfs/api.php
@@ -0,0 +1,82 @@
+ "SET NAMES utf8", PDO::ATTR_EMULATE_PREPARES => false];
+ $pdo = new PDO("mysql:host=$host;port=3306;dbname=$dbname;charset=utf8;protocol=tcp", $username, $password, $options);
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $planetId = isset($_GET['planet']) ? $_GET['planet'] : '';
+
+ $allowedTables = [
+ 'mercury' => 'MERCURY',
+ 'venus' => 'VENUS',
+ 'earth' => 'EARTH',
+ 'mars' => 'MARS',
+ 'jupiter' => 'JUPITER',
+ 'saturn' => 'SATURN',
+ 'uranus' => 'URANUS',
+ 'neptune' => 'NEPTUNE',
+ 'sun' => 'SUN',
+ 'moon' => 'MOON',
+ ];
+
+ if ($planetId === 'quiz') {
+ $queries = [];
+ $seed = date('Ymd');
+ foreach ($allowedTables as $key => $table) {
+ $planetName = ucfirst($key);
+ $queries[] = "(SELECT explanation, '$planetName' AS planete_nom, url FROM $table WHERE explanation IS NOT NULL AND explanation != '' ORDER BY RAND($seed) LIMIT 3)";
+ }
+ $unionQuery = implode(' UNION ALL ', $queries);
+
+ $stmt = $pdo->prepare("SELECT * FROM ($unionQuery) as all_data ORDER BY RAND($seed) LIMIT 10");
+ $stmt->execute();
+ $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
+
+ $questions = [];
+ $allPlanets = ['Mercury', 'Venus', 'Earth', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune','Sun' , 'Moon'];
+
+ foreach ($results as $row) {
+ $correctEn = $row['planete_nom'];
+
+ $optionsEn = [$correctEn];
+ $others = array_diff($allPlanets, [$correctEn]);
+ shuffle($others);
+ $optionsEn = array_merge($optionsEn, array_slice($others, 0, 3));
+ shuffle($optionsEn);
+
+ $text = substr($row['explanation'], 0, 200) . '...';
+
+ $questions[] = [
+ 'q' => "Which celestial body does this description refer to? « " . $text . " »",
+ 'options' => $optionsEn,
+ 'a' => $correctEn,
+ 'img' => isset($row['url']) ? $row['url'] : ''
+ ];
+ }
+
+ echo json_encode($questions);
+ exit;
+ }
+
+ if (!array_key_exists($planetId, $allowedTables)) {
+ echo json_encode([]);
+ exit;
+ }
+
+ $tableName = $allowedTables[$planetId];
+ $stmt = $pdo->prepare("SELECT * FROM $tableName");
+ $stmt->execute();
+
+ $data = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ echo json_encode($data);
+} catch (PDOException $e) {
+ http_response_code(500);
+ echo json_encode(['error' => 'Database error: ' . $e->getMessage()]);
+}
\ No newline at end of file
diff --git a/3ds/romfs/contact.php b/3ds/romfs/contact.php
new file mode 100644
index 0000000..72710ca
--- /dev/null
+++ b/3ds/romfs/contact.php
@@ -0,0 +1,88 @@
+Format non autorisé. Seuls les fichiers JPG, PNG et PDF sont acceptés.
";
+ $has_error = true;
+ } elseif ($file_size > $max_size) {
+ $message_status = "Le fichier est trop volumineux (maximum 5 Mo).
";
+ $has_error = true;
+ } else {
+ $upload_dir = 'UPLOADS/';
+ if (!is_dir($upload_dir)) {
+ mkdir($upload_dir, 0777, true);
+ }
+
+ $safe_file_name = time() . '_' . preg_replace('/[^a-zA-Z0-9.\-_]/', '', $file_name);
+ $target_path = $upload_dir . $safe_file_name;
+
+ if (move_uploaded_file($file_tmp_name, $target_path)) {
+ $file_path = $target_path;
+ } else {
+ $message_status = "Erreur lors de la sauvegarde du fichier.
";
+ $has_error = true;
+ }
+ }
+ }
+
+ if (!$has_error) {
+ try {
+ $host = '172.22.0.3';
+ $dbname = 'OpenPlanetsMaps';
+ $db_user = 'root';
+ $db_pass = 'admin123';
+
+ $options = [PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8", PDO::ATTR_EMULATE_PREPARES => false];
+ $pdo = new PDO("mysql:host=$host;port=3306;dbname=$dbname;charset=utf8;protocol=tcp", $db_user, $db_pass, $options);
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+ $stmt = $pdo->prepare("INSERT INTO CONTACT (email, objet, demande, fichier, date_demande) VALUES (?, ?, ?, ?, NOW())");
+ $stmt->execute([$email, $subject, $message, $file_path]);
+
+ $message_status = "Votre demande a été enregistrée avec succès dans la base de données !
";
+ } catch (PDOException $e) {
+ $message_status = "Erreur de base de données : " . htmlspecialchars($e->getMessage()) . "
";
+ }
+ }
+}
+?>
+
+
+
+
+ Contact - OpenPlanetsMaps
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3ds/romfs/index.html b/3ds/romfs/index.html
new file mode 100644
index 0000000..44a86f1
--- /dev/null
+++ b/3ds/romfs/index.html
@@ -0,0 +1,397 @@
+
+
+
+
+
+
+ OpenPlanetsMaps
+
+
+
+
+
+
+
+
+
+ Open Planets Maps
+
+ Contact
+ Admin
+
+
+
+
+
+
+
+
+
+
+
+
+
Space Exploration
+
Navigate through the solar system and discover the unique characteristics of each planet with our interactive maps.
+
+
+
Open Data
+
Access a topographic database from space agencies, centralized in an open source tool.
+
+
+
+
Solar System - 8 Planets - Open Source Mapping - Topographic Data - Interactive Exploration...
+
+ Ready for launch? Open the side menu (☰) and select a destination to begin your journey.
+
+
+
+
+
+
+
+ Mercury is the closest planet to the Sun and the smallest in the solar system. Its surface is heavily cratered, resembling our Moon, and it experiences extreme temperature variations.
+
+
Distance from the Sun: 58 million km • Temperature: -180°C to 430°C • Surface area: 74.8 million km² • Length of day: 59 Earth days
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ Venus is the second planet in the solar system and the hottest. Its highly dense atmosphere causes an extreme greenhouse effect, and its surface is masked by thick clouds of sulfuric acid.
+
+
Distance from the Sun: 108 million km • Average temperature: 462°C • Surface area: 460 million km² • Length of day: 243 Earth days
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ Our home planet, Earth, is the third planet in the solar system and the only one known to harbor life. It is distinguished by its vast oceans of liquid water that cover more than 70% of its surface.
+
+
Distance from the Sun: 150 million km (1 AU) • Average temperature: 15°C • Surface area: 510 million km² • Natural satellites: 1 (The Moon)
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ Nicknamed the « Red Planet » due to the iron oxide on its surface, Mars has polar ice caps, the largest volcano in the solar system (Olympus Mons), and an immense canyon (Valles Marineris).
+
+
Distance from the Sun: 227.9 million km • Average temperature: -63°C • Surface area: 144.8 million km² • Gravity: 3.72 m/s²
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ Jupiter is the largest planet in our solar system. This gas giant is famous for its Great Red Spot, a gigantic anticyclonic storm, and possesses dozens of fascinating moons.
+
+
Distance from the Sun: 778 million km • Average temperature: -110°C • Surface area: 61.4 billion km² • Natural satellites: 95 known
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ Instantly recognizable by its spectacular system of rings composed of ice and rock particles, Saturn is a vast gas giant with extremely violent winds.
+
+
Distance from the Sun: 1.43 billion km • Average temperature: -140°C • Surface area: 42.7 billion km² • Natural satellites: 146 known
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ Uranus is an ice giant whose axis of rotation is highly tilted, making it appear to « roll » along its orbit. Its beautiful cyan tint is due to the presence of methane.
+
+
Distance from the Sun: 2.87 billion km • Average temperature: -195°C • Surface area: 8.1 billion km² • Length of year: 84 Earth years
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+
+
+ The farthest planet from the Sun is another ice giant, Neptune. It is known for its deep azure blue color and its supersonic winds, the fastest in the entire solar system.
+
+
Distance from the Sun: 4.5 billion km • Average temperature: -200°C • Surface area: 7.6 billion km² • Wind speed: up to 2,100 km/h
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+ The Sun is the star at the center of our solar system. It alone accounts for about 99.8% of the solar system's mass and provides the energy necessary to sustain life on Earth.
+
+
Type: Yellow dwarf • Surface temperature: 5,500°C • Distance to Earth: 150 million km (1 AU) • Age: 4.6 billion years
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+
+
+ The Moon is Earth's only natural satellite. It is the fifth largest satellite in the solar system and the only non-terrestrial celestial body to have been visited by humans.
+
+
Distance to Earth: 384,400 km • Temperature: -173°C to 127°C • Gravity: 1.62 m/s² • Orbit duration: 27.3 days
+
+
+
+
+
+ Name
+ Image
+ Date
+
+
+
+ Waiting for data...
+
+
+
+
+
+
+ Test your knowledge of the solar system! Answer the questions below to see if you are a true space expert.
+
+
+
◈ DAILY CHALLENGE
+
Every day at midnight, the onboard computer compiles our archives to generate a new unique 10-question Quiz. Practice daily to perfect your knowledge!
+
+
+
+
Loading the Quiz...
+
+
+
◈ SOURCE — MISSION IMAGE
+
+
+
+
+
Restart the Quiz
+
+
+
+
+
+
+
+
+
✕
+
+
+
+
Project
+
OpenPlanetsMaps is an open source tool for interactive mapping of the solar system. Topographic data comes from the main global space agencies.
+
+
+
Data & Sources
+
+ NASA — National Aeronautics and Space Administration
+ ESA — European Space Agency
+ JAXA — Japan Aerospace Exploration Agency
+ USGS — Astrogeology Science Center
+
+
+
+
3D Models
+
+ Sketchfab — Hosting & rendering of interactive models
+ Models under Creative Commons licenses
+
+
+
+
Technologies
+
+ HTML / CSS / JS — Front-end
+ PHP + MySQL — Back-end & database
+ Orbitron, Space Grotesk, Space Mono — Google Fonts
+
+
+
+
License
+
This project is freely distributed. Scientific data remains the property of their respective organizations.
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3ds/romfs/main.js b/3ds/romfs/main.js
new file mode 100644
index 0000000..debf403
--- /dev/null
+++ b/3ds/romfs/main.js
@@ -0,0 +1,401 @@
+function toggleSidebar() {
+ document.getElementById('sidebar').classList.toggle('open');
+}
+
+function showLayer(layerId) {
+ document.querySelectorAll('.layer').forEach(layer => {
+ layer.classList.remove('active');
+ });
+
+ document.getElementById('layer-' + layerId).classList.add('active');
+
+ document.body.className = '';
+ document.body.classList.add('theme-' + layerId);
+
+ if (layerId === 'Quiz') {
+ initQuiz();
+ } else if (layerId !== 'home') {
+ fetchData(layerId);
+ }
+
+ toggleSidebar();
+}
+
+const planetData = {};
+const planetCols = {};
+
+function wireSearch(planetId) {
+ const layer = document.getElementById('layer-' + planetId);
+ if (!layer) return;
+ const input = layer.querySelector('.search-bar input');
+ if (!input) return;
+
+ const fresh = input.cloneNode(true);
+ input.parentNode.replaceChild(fresh, input);
+
+ fresh.addEventListener('input', () => {
+ filterTable(planetId, fresh.value.trim());
+ });
+}
+
+function filterTable(planetId, query) {
+ const tbody = document.getElementById('tbody-' + planetId);
+ if (!tbody) return;
+
+ const rows = Array.from(tbody.querySelectorAll('tr'));
+ const cols = planetCols[planetId] || [];
+ const data = planetData[planetId] || [];
+
+ const titleIndices = cols.reduce((acc, col, i) => {
+ const c = col.toLowerCase();
+ if (c === 'name' || c.includes('title')) {
+ acc.push(i);
+ }
+ return acc;
+ }, []);
+
+ const searchIndices = titleIndices.length > 0
+ ? titleIndices
+ : cols.reduce((acc, col, i) => {
+ const c = col.toLowerCase();
+ if (!c.includes('url') && !c.includes('desc') && !c.includes('expl') && c !== 'image' && c !== 'img') {
+ acc.push(i);
+ }
+ return acc;
+ }, []);
+
+ const tokens = query.toLowerCase().split(/\s+/).filter(Boolean);
+
+ const tableContainer = tbody.closest('.table-container');
+ const showMoreBtn = tableContainer ? tableContainer.querySelector('.show-more-btn') : null;
+
+ if (tokens.length === 0) {
+ rows.forEach((tr, index) => {
+ tr.style.display = '';
+ if (data.length > 10) {
+ if (index >= 10) tr.classList.add('hidden-row');
+ else tr.classList.remove('hidden-row');
+ }
+ });
+ if (showMoreBtn) showMoreBtn.style.display = '';
+ return;
+ }
+
+ if (showMoreBtn) showMoreBtn.style.display = 'none';
+
+ rows.forEach((tr, index) => {
+ const rowObj = data[index];
+ if (!rowObj) { tr.style.display = 'none'; return; }
+
+ const haystack = searchIndices
+ .map(i => String(rowObj[cols[i]] || '').toLowerCase())
+ .join(' ');
+
+ const matches = tokens.every(token => haystack.includes(token));
+
+ tr.classList.remove('hidden-row');
+ tr.style.display = matches ? '' : 'none';
+ });
+}
+
+async function fetchData(planetId) {
+ const tbody = document.getElementById('tbody-' + planetId);
+ if (!tbody) return;
+
+ if (tbody.getAttribute('data-loaded') === 'true') {
+ wireSearch(planetId);
+ return;
+ }
+
+ tbody.innerHTML = 'Loading data from the database... ';
+
+ try {
+ const response = await fetch(`api.php?planet=${planetId}`);
+
+ if (!response.ok) {
+ const errorData = await response.json().catch(() => ({}));
+ throw new Error(errorData.error || `HTTP Error: ${response.status}`);
+ }
+
+ const data = await response.json();
+
+ tbody.innerHTML = '';
+
+ if (data.length === 0) {
+ tbody.innerHTML = 'No data available at the moment. ';
+ return;
+ }
+
+ const columns = Object.keys(data[0]).filter(col => col.toLowerCase() !== 'copyright');
+
+ planetData[planetId] = data;
+ planetCols[planetId] = columns;
+
+ const thead = tbody.parentElement.querySelector('thead');
+ thead.innerHTML = '' + columns.map(col => {
+ const colLower = col.toLowerCase();
+ const isDesc = colLower.includes('desc') || colLower.includes('expl');
+ const isUrl = colLower.includes('url') || colLower === 'image' || colLower === 'img';
+
+ let className = '';
+ if (isDesc) className = ' class="col-desc"';
+ else if (isUrl) className = ' class="col-url"';
+ return `${col.toUpperCase()} `;
+ }).join('') + ' ';
+
+ data.forEach((row, index) => {
+ const tr = document.createElement('tr');
+
+ if (index >= 10) tr.classList.add('hidden-row');
+
+ let rowHtml = '';
+ columns.forEach(col => {
+ const colLower = col.toLowerCase();
+ const colLabel = col.toUpperCase();
+ if (colLower.includes('url') || colLower === 'image' || colLower === 'img') {
+ const url = row[col];
+ if (url && url.trim() !== '') {
+ rowHtml += `
+
+ ${url}
+
+ `;
+ } else {
+ rowHtml += `N/A `;
+ }
+ } else if (colLower.includes('desc') || colLower.includes('expl')) {
+ const text = row[col] || '';
+ let fontSizeStyle = '';
+ if (text.length > 200) fontSizeStyle = ' font-size: 0.75rem;';
+ else if (text.length > 100) fontSizeStyle = ' font-size: 0.85rem;';
+ rowHtml += `${text} `;
+ } else {
+ rowHtml += `${row[col]} `;
+ }
+ });
+
+ tr.innerHTML = rowHtml;
+ tbody.appendChild(tr);
+ });
+
+ const tableContainer = tbody.closest('.table-container');
+ if (tableContainer) {
+ tableContainer.style.overflowX = 'auto';
+ tableContainer.style.maxWidth = '100%';
+ tableContainer.style.WebkitOverflowScrolling = 'touch';
+ }
+ const existingBtn = tableContainer.querySelector('.show-more-btn');
+ if (existingBtn) existingBtn.remove();
+
+ if (data.length > 10) {
+ const btn = document.createElement('button');
+ btn.innerHTML = 'Show more ⬇';
+ btn.className = 'show-more-btn';
+ btn.onclick = () => {
+ tbody.querySelectorAll('.hidden-row').forEach(row => row.classList.remove('hidden-row'));
+ btn.remove();
+ };
+ tableContainer.appendChild(btn);
+ }
+
+ tbody.setAttribute('data-loaded', 'true');
+
+ wireSearch(planetId);
+
+ } catch (error) {
+ console.error("Database connection error:", error);
+ tbody.innerHTML = `Technical error: ${error.message} `;
+ }
+}
+
+let quizQuestions = [];
+let currentQuizIndex = 0;
+let quizScore = 0;
+
+async function initQuiz() {
+ currentQuizIndex = 0;
+ quizScore = 0;
+ document.getElementById('quiz-restart-btn').style.display = 'none';
+ document.getElementById('quiz-score').textContent = '';
+
+ if (quizQuestions.length === 0) {
+ document.getElementById('quiz-question').textContent = "Loading today's Quiz...";
+ document.getElementById('quiz-options').innerHTML = '';
+
+ try {
+ const response = await fetch(`api.php?planet=quiz`);
+ if (!response.ok) {
+ let errMsg = "Network error";
+ try {
+ const errData = await response.json();
+ if (errData.error) errMsg = errData.error;
+ } catch (e) {}
+ throw new Error(errMsg);
+ }
+ quizQuestions = await response.json();
+
+ if (quizQuestions.length === 0) {
+ document.getElementById('quiz-question').textContent = "Not enough data in the database to generate a quiz.";
+ return;
+ }
+ } catch (error) {
+ console.error("Quiz Error:", error);
+ document.getElementById('quiz-question').textContent = "Error: " + error.message;
+ return;
+ }
+ }
+
+ showQuizQuestion();
+}
+
+function showQuizQuestion() {
+ const preview = document.getElementById('quiz-img-preview');
+
+ if (currentQuizIndex >= quizQuestions.length) {
+ document.getElementById('quiz-question').textContent = "Today's Quiz finished!";
+ document.getElementById('quiz-options').innerHTML = "";
+ document.getElementById('quiz-score').textContent = `Your score: ${quizScore} / ${quizQuestions.length}`;
+ document.getElementById('quiz-restart-btn').style.display = 'inline-block';
+ if (preview) preview.classList.remove('visible');
+ return;
+ }
+
+ const qObj = quizQuestions[currentQuizIndex];
+ document.getElementById('quiz-question').innerText = `Question ${currentQuizIndex + 1}/${quizQuestions.length}:\n\n${qObj.q}`;
+
+ const optionsContainer = document.getElementById('quiz-options');
+ optionsContainer.innerHTML = '';
+
+ qObj.options.forEach(opt => {
+ const btn = document.createElement('button');
+ btn.className = 'quiz-btn';
+ btn.textContent = opt;
+ btn.onclick = () => checkAnswer(opt, qObj.a, btn);
+ optionsContainer.appendChild(btn);
+ });
+
+ if (preview) {
+ preview.classList.remove('visible');
+ const oldImg = preview.querySelector('img');
+ const oldVid = preview.querySelector('video');
+ if (oldImg) { oldImg.src = ''; oldImg.style.display = 'none'; }
+ if (oldVid) { oldVid.pause(); oldVid.src = ''; oldVid.style.display = 'none'; }
+
+ if (qObj.img && qObj.img.trim() !== '') {
+ const url = qObj.img.trim();
+ const isVideo = /\.(mp4|webm|ogg|mov)(\?.*)?$/i.test(url);
+ const caption = preview.querySelector('.quiz-img-caption');
+
+ requestAnimationFrame(() => {
+ if (isVideo) {
+ let vid = preview.querySelector('video');
+ if (!vid) {
+ vid = document.createElement('video');
+ vid.controls = true;
+ vid.preload = 'metadata';
+ vid.style.display = 'none';
+ preview.querySelector('.quiz-img-label').insertAdjacentElement('afterend', vid);
+ }
+ vid.src = url;
+ vid.style.display = 'block';
+ if (oldImg) oldImg.style.display = 'none';
+ } else {
+ if (oldImg) {
+ oldImg.src = url;
+ oldImg.alt = 'Image associated with the question';
+ oldImg.style.display = 'block';
+ }
+ if (oldVid) oldVid.style.display = 'none';
+ }
+ caption.textContent = url;
+ preview.classList.add('visible');
+ });
+ }
+ }
+}
+
+function checkAnswer(selected, correct, btn) {
+ const optionsContainer = document.getElementById('quiz-options');
+ const buttons = optionsContainer.querySelectorAll('.quiz-btn');
+
+ buttons.forEach(b => {
+ b.disabled = true;
+ b.style.cursor = 'default';
+ });
+
+ if (selected === correct) {
+ btn.classList.add('correct');
+ quizScore++;
+ } else {
+ btn.classList.add('wrong');
+ buttons.forEach(b => {
+ if (b.textContent === correct) b.classList.add('correct');
+ });
+ }
+
+ setTimeout(() => {
+ currentQuizIndex++;
+ showQuizQuestion();
+ }, 1800);
+}
+
+function openCredits() {
+ document.getElementById('credits-panel').classList.add('open');
+ document.getElementById('credits-overlay').classList.add('open');
+ document.body.style.overflow = 'hidden';
+}
+
+function closeCredits() {
+ document.getElementById('credits-panel').classList.remove('open');
+ document.getElementById('credits-overlay').classList.remove('open');
+ document.body.style.overflow = '';
+}
+
+document.addEventListener('DOMContentLoaded', () => {
+ const overlay = document.getElementById('credits-overlay');
+ if (overlay) overlay.addEventListener('click', closeCredits);
+
+ document.addEventListener('keydown', e => {
+ if (e.key === 'Escape') closeCredits();
+ });
+
+ const isMobile = window.innerWidth <= 768 || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+ const isElectron = navigator.userAgent.toLowerCase().includes('electron');
+ const isCapacitor = window.Capacitor !== undefined; // Détecte l'application mobile native
+
+ if (isCapacitor) {
+ document.body.classList.add('is-mobile-app');
+ }
+
+ if (isMobile || isElectron || isCapacitor) {
+ const iframes = document.querySelectorAll('iframe');
+ iframes.forEach(iframe => {
+ const fallback = document.createElement('div');
+ if (isElectron) {
+ fallback.textContent = "3D models are not compatible on the desktop app";
+ } else if (isCapacitor) {
+ fallback.textContent = "3D models are not compatible on the mobile app";
+ } else {
+ fallback.textContent = "functionality not available on mobile devices";
+ }
+ fallback.style.display = "flex";
+ fallback.style.alignItems = "center";
+ fallback.style.justifyContent = "center";
+
+ // Correction du responsive : on empêche la boîte de déborder de l'écran
+ fallback.style.width = "100%";
+ fallback.style.maxWidth = "100%";
+ fallback.style.boxSizing = "border-box";
+
+ fallback.style.minHeight = "200px";
+ fallback.style.backgroundColor = "#1e293b";
+ fallback.style.color = "#f87171";
+ fallback.style.border = "1px solid #334155";
+ fallback.style.borderRadius = "8px";
+ fallback.style.padding = "20px";
+ fallback.style.textAlign = "center";
+
+ iframe.parentNode.replaceChild(fallback, iframe);
+ });
+ }
+});
\ No newline at end of file
diff --git a/3ds/romfs/style.css b/3ds/romfs/style.css
new file mode 100644
index 0000000..8441bc3
--- /dev/null
+++ b/3ds/romfs/style.css
@@ -0,0 +1,593 @@
+@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=Orbitron:wght@400;600;700;900&family=Space+Mono:wght@400;700&display=swap');
+
+:root {
+ --theme-color: #4f8eff;
+ --theme-glow: rgba(79,142,255,.35);
+ --theme-subtle:rgba(79,142,255,.08);
+ --bg-deep: #020408; --bg-mid: #060d18;
+ --text-primary: #e8f0ff; --text-secondary: #7a9bc4; --text-muted: #3d5478;
+ --border: rgba(79,142,255,.15);
+}
+body.theme-home { --theme-color:#4f8eff; --theme-glow:rgba(79,142,255,.4); --bg-deep:#020408; --bg-mid:#060d18; }
+body.theme-mercury { --theme-color:#c0a080; --theme-glow:rgba(192,160,128,.4); --bg-deep:#0c0906; --bg-mid:#1a1008; }
+body.theme-venus { --theme-color:#ff9230; --theme-glow:rgba(255,146,48,.4); --bg-deep:#0d0600; --bg-mid:#1e0e00; }
+body.theme-earth { --theme-color:#00cfff; --theme-glow:rgba(0,207,255,.4); --bg-deep:#010b10; --bg-mid:#031520; }
+body.theme-mars { --theme-color:#ff5040; --theme-glow:rgba(255,80,64,.4); --bg-deep:#0d0200; --bg-mid:#1e0600; }
+body.theme-jupiter { --theme-color:#ffb347; --theme-glow:rgba(255,179,71,.4); --bg-deep:#0d0800; --bg-mid:#1e1200; }
+body.theme-saturn { --theme-color:#f5d060; --theme-glow:rgba(245,208,96,.4); --bg-deep:#0c0900; --bg-mid:#1c1500; }
+body.theme-uranus { --theme-color:#40e8d0; --theme-glow:rgba(64,232,208,.4); --bg-deep:#000c0b; --bg-mid:#001a18; }
+body.theme-neptune { --theme-color:#2060ff; --theme-glow:rgba(32,96,255,.4); --bg-deep:#000208; --bg-mid:#000510; }
+body.theme-sun { --theme-color:#ffcc44; --theme-glow:rgba(255,180,40,.55); --theme-subtle:rgba(255,180,40,.09); --bg-deep:#0d0500; --bg-mid:#200c00; --border:rgba(255,180,40,.2); --text-primary:#fff5dc; --text-secondary:#c4923a; --text-muted:#6b4010; }
+body.theme-moon { --theme-color:#c8cfe8; --theme-glow:rgba(200,207,232,.35); --theme-subtle:rgba(200,207,232,.06); --bg-deep:#060608; --bg-mid:#0e0f14; --border:rgba(200,207,232,.12); --text-primary:#dde2f0; --text-secondary:#7e8ba8; --text-muted:#3c4258; }
+body.theme-Quiz { --theme-color:#7eb8f7; --theme-glow:rgba(126,184,247,.35); --theme-subtle:rgba(126,184,247,.07); --bg-deep:#020510; --bg-mid:#060e24; --border:rgba(126,184,247,.13); --text-primary:#ddeeff; --text-secondary:#6a90b8; --text-muted:#2e4a6a; }
+
+*,*::before,*::after { margin:0; padding:0; box-sizing:border-box; }
+
+html, body { max-width:100vw; overflow-x:hidden; }
+body {
+ background:var(--bg-deep); color:var(--text-primary);
+ font-family:'Space Grotesk',sans-serif;
+ display:flex; flex-direction:column; min-height:100vh; overflow-x:hidden;
+ transition:background-color .8s ease, color .3s ease;
+}
+
+.bg-animated {
+ position:fixed; inset:0; z-index:-2;
+ background:radial-gradient(ellipse at 20% 10%, var(--bg-mid) 0%, var(--bg-deep) 60%);
+ transition:background 1s ease;
+}
+.bg-animated::before, .bg-animated::after {
+ content:''; position:absolute; inset:0;
+}
+.bg-animated::before {
+ background-image:
+ radial-gradient(1px 1px at 10% 15%,rgba(255,255,255,.8) 0%,transparent 100%),
+ radial-gradient(1px 1px at 25% 40%,rgba(255,255,255,.5) 0%,transparent 100%),
+ radial-gradient(1.5px 1.5px at 40% 8%,rgba(255,255,255,.9) 0%,transparent 100%),
+ radial-gradient(1px 1px at 55% 60%,rgba(255,255,255,.4) 0%,transparent 100%),
+ radial-gradient(1px 1px at 70% 25%,rgba(255,255,255,.7) 0%,transparent 100%),
+ radial-gradient(1.5px 1.5px at 80% 70%,rgba(255,255,255,.6) 0%,transparent 100%),
+ radial-gradient(1px 1px at 90% 45%,rgba(255,255,255,.5) 0%,transparent 100%),
+ radial-gradient(1px 1px at 15% 80%,rgba(255,255,255,.6) 0%,transparent 100%),
+ radial-gradient(1px 1px at 35% 90%,rgba(255,255,255,.4) 0%,transparent 100%),
+ radial-gradient(1.5px 1.5px at 60% 85%,rgba(255,255,255,.7) 0%,transparent 100%),
+ radial-gradient(1px 1px at 82% 15%,rgba(255,255,255,.8) 0%,transparent 100%),
+ radial-gradient(1px 1px at 5% 55%,rgba(255,255,255,.5) 0%,transparent 100%),
+ radial-gradient(1.5px 1.5px at 92% 88%,rgba(255,255,255,.6) 0%,transparent 100%),
+ radial-gradient(1px 1px at 67% 5%,rgba(255,255,255,.9) 0%,transparent 100%);
+ animation:starTwinkle 8s ease-in-out infinite alternate;
+}
+.bg-animated::after {
+ background-image:
+ radial-gradient(1px 1px at 18% 30%,rgba(255,255,255,.6) 0%,transparent 100%),
+ radial-gradient(1px 1px at 33% 65%,rgba(255,255,255,.4) 0%,transparent 100%),
+ radial-gradient(1.5px 1.5px at 48% 22%,rgba(255,255,255,.7) 0%,transparent 100%),
+ radial-gradient(1px 1px at 63% 75%,rgba(255,255,255,.5) 0%,transparent 100%),
+ radial-gradient(1px 1px at 75% 48%,rgba(255,255,255,.8) 0%,transparent 100%),
+ radial-gradient(1px 1px at 88% 30%,rgba(255,255,255,.4) 0%,transparent 100%),
+ radial-gradient(1.5px 1.5px at 12% 68%,rgba(255,255,255,.6) 0%,transparent 100%),
+ radial-gradient(1px 1px at 96% 60%,rgba(255,255,255,.5) 0%,transparent 100%),
+ radial-gradient(1px 1px at 52% 38%,rgba(255,255,255,.3) 0%,transparent 100%);
+ animation:starTwinkle 12s ease-in-out infinite alternate-reverse;
+}
+body::before {
+ content:''; position:fixed; inset:0; z-index:-1; pointer-events:none;
+ background:
+ radial-gradient(ellipse 40% 30% at 15% 20%, var(--theme-glow), transparent),
+ radial-gradient(ellipse 25% 35% at 85% 75%, var(--theme-glow), transparent);
+ transition:background 1s ease;
+}
+body.theme-sun::before {
+ background:
+ radial-gradient(ellipse 50% 35% at 80% 15%,rgba(255,150,20,.3),transparent),
+ radial-gradient(ellipse 35% 50% at 10% 80%,rgba(255,100,0,.2),transparent);
+}
+body.theme-moon::before {
+ background:
+ radial-gradient(ellipse 45% 30% at 85% 10%,rgba(200,207,232,.18),transparent),
+ radial-gradient(ellipse 30% 45% at 5% 90%,rgba(150,160,200,.12),transparent);
+}
+@keyframes starTwinkle {
+ 0% { opacity:.5; }
+ 50% { opacity:1; }
+ 100% { opacity:.65; }
+}
+
+#safe-area-block {
+ position: sticky; top: 0; z-index: 101;
+ width: 100%;
+ height: env(safe-area-inset-top);
+ background: var(--bg-deep);
+}
+
+header {
+ display:flex; justify-content:space-between; align-items:center;
+ padding:0 2rem;
+ height:64px;
+ background:rgba(2,4,8,.75); backdrop-filter:blur(20px);
+ border-bottom:1px solid var(--border);
+ position:sticky; top:env(safe-area-inset-top); z-index:100;
+ transition:border-color .6s ease;
+}
+header::after {
+ content:''; position:absolute; bottom:0; left:0; right:0; height:1px;
+ background:linear-gradient(90deg,transparent,var(--theme-color),transparent);
+ opacity:.6; transition:background .6s ease;
+}
+header h1 {
+ font-family:'Orbitron',monospace; font-size:1.1rem; font-weight:700;
+ letter-spacing:.15em; text-transform:uppercase;
+ color:var(--theme-color); text-shadow:0 0 20px var(--theme-glow);
+ transition:color .6s ease, text-shadow .6s ease;
+}
+header h1:hover { animation:glitch .4s steps(1) forwards; }
+
+.menu-icon, .help-btn {
+ cursor:pointer; background:transparent;
+ border:1px solid var(--border); border-radius:6px; padding:.45rem 1rem;
+ color:var(--text-secondary); font-family:'Space Mono',monospace;
+ font-size:.8rem; letter-spacing:.08em;
+ transition:all .2s ease; position:relative; overflow:hidden;
+}
+.menu-icon::before, .help-btn::before {
+ content:''; position:absolute; inset:0;
+ background:var(--theme-subtle); opacity:0; transition:opacity .2s ease;
+}
+.menu-icon:hover::before, .help-btn:hover::before { opacity:1; }
+.menu-icon:hover, .help-btn:hover {
+ border-color:var(--theme-color); color:var(--theme-color);
+ box-shadow:0 0 12px var(--theme-glow);
+}
+
+.sidebar {
+ position:fixed; top:0; left:-300px; width:280px; height:100vh;
+ background:rgba(2,6,14,.96); backdrop-filter:blur(24px);
+ border-right:1px solid var(--border);
+ transition:left .35s cubic-bezier(.4,0,.2,1), border-color .6s ease;
+ z-index:1000; padding-top:5rem; overflow-y:auto;
+}
+.sidebar::before {
+ content:'NAVIGATION'; position:absolute; top:1.5rem; left:1.5rem;
+ font-family:'Space Mono',monospace; font-size:.65rem; letter-spacing:.25em;
+ color:var(--text-muted);
+}
+.sidebar.open { left:0; }
+.sidebar ul { list-style:none; }
+.sidebar li {
+ padding:.9rem 1.75rem; cursor:pointer;
+ font-family:'Orbitron',monospace; font-size:.7rem; font-weight:600;
+ letter-spacing:.12em; text-transform:uppercase; color:var(--text-secondary);
+ transition:all .2s ease; border-left:2px solid transparent; position:relative;
+}
+.sidebar li::after {
+ content:'→'; position:absolute; right:1.5rem; top:50%;
+ transform:translateY(-50%) translateX(-4px);
+ opacity:0; transition:all .2s ease; font-family:monospace;
+}
+.sidebar li:hover {
+ color:var(--theme-color); border-left-color:var(--theme-color);
+ background:var(--theme-subtle); padding-left:2.25rem;
+ text-shadow:0 0 10px var(--theme-glow);
+}
+.sidebar li:hover::after { opacity:1; transform:translateY(-50%) translateX(0); }
+.sidebar li.menu-category {
+ font-family:'Space Mono',monospace; font-size:.6rem; letter-spacing:.3em;
+ color:var(--text-muted); cursor:default; border-left:none;
+ padding:1.2rem 1.75rem .4rem; pointer-events:none;
+}
+.sidebar li.menu-category::after { display:none; }
+.sidebar li.menu-category:hover { background:none; padding-left:1.75rem; text-shadow:none; color:var(--text-muted); }
+
+#content-area {
+ flex:1; padding:2.5rem; display:flex;
+ max-width:1400px; margin:0 auto; width:100%;
+}
+.layer {
+ display:none; width:100%; flex-direction:column; flex:1; text-align:center;
+ animation:layerReveal .5s cubic-bezier(.4,0,.2,1) both;
+}
+.layer.active { display:flex; }
+
+.main-img {
+ margin-bottom:2.5rem; position:relative;
+ border-radius:12px; overflow:hidden; border:1px solid var(--border);
+ box-shadow:0 20px 60px rgba(0,0,0,.6), 0 0 60px var(--theme-glow);
+ transition:box-shadow .6s ease, border-color .6s ease, transform .4s ease;
+}
+.main-img:hover { transform:perspective(1200px) rotateX(1deg) scale(1.005); }
+.main-img::before {
+ content:''; position:absolute; inset:0; border-radius:12px;
+ box-shadow:inset 0 0 30px rgba(0,0,0,.3); z-index:1; pointer-events:none;
+}
+.main-img iframe, .main-img img { width:100%; height:70vh; border:none; display:block; }
+.main-img img { object-fit:cover; }
+.sketchfab-embed-wrapper p { font-family:'Space Mono',monospace; font-size:.65rem; color:var(--text-muted); padding:.4rem .75rem; text-align:right; }
+.sketchfab-embed-wrapper a { color:var(--theme-color); text-decoration:none; }
+
+.flex-row {
+ display:flex; flex-wrap:wrap; justify-content:center;
+ gap:1.5rem; margin:0 auto 2.5rem; max-width:900px;
+}
+.flex-row .box { flex:1; min-width:280px; }
+.box {
+ padding:1.75rem; background:rgba(255,255,255,.02);
+ border:1px solid var(--border); border-radius:10px;
+ text-align:left; position:relative; overflow:hidden;
+ transition:border-color .3s, box-shadow .3s, transform .3s;
+}
+.box::before {
+ content:''; position:absolute; top:0; left:-100%; right:100%; height:2px;
+ background:linear-gradient(90deg,transparent,var(--theme-color),transparent);
+ transition:left .4s ease, right .4s ease;
+}
+.box:hover::before { left:0; right:0; }
+.box:hover { border-color:var(--theme-color); box-shadow:0 8px 30px var(--theme-glow); transform:translateY(-2px); }
+.box h2 {
+ font-family:'Orbitron',monospace; font-size:.75rem; font-weight:700;
+ letter-spacing:.2em; text-transform:uppercase;
+ color:var(--theme-color); margin-bottom:.85rem; text-shadow:0 0 15px var(--theme-glow);
+}
+.box p { line-height:1.7; color:var(--text-secondary); font-size:.9rem; }
+
+.desc-box {
+ max-width:780px; margin:0 auto 2.5rem; line-height:1.75;
+ color:var(--text-secondary); font-size:.95rem; padding:1.25rem 1.75rem;
+ background:rgba(255,255,255,.02); border:1px solid var(--border); border-radius:8px;
+ border-left:3px solid var(--theme-color); text-align:left;
+ transition:border-color .6s ease;
+}
+#layer-home .desc-box {
+ font-family:'Space Mono',monospace; font-size:.85rem;
+ color:var(--theme-color); text-align:center;
+ background:var(--theme-subtle); border:1px solid var(--theme-color);
+ letter-spacing:.05em; opacity:.8;
+}
+
+.ticker-wrap {
+ width:100%; overflow:hidden; padding:.65rem 0; margin-bottom:2.5rem;
+ border-top:1px solid var(--border); border-bottom:1px solid var(--border);
+ position:relative; transition:border-color .6s ease;
+}
+.ticker-wrap::before {
+ content:'◈ TELEMETRY'; position:absolute; left:0; top:50%; transform:translateY(-50%);
+ font-family:'Space Mono',monospace; font-size:.6rem; letter-spacing:.2em;
+ color:var(--theme-color); background:var(--bg-deep); padding:0 .75rem; z-index:1;
+ transition:color .6s, background .6s;
+}
+.ticker-wrap::after {
+ content:''; position:absolute; right:0; top:0; bottom:0; width:80px;
+ background:linear-gradient(90deg,transparent,var(--bg-deep)); z-index:1;
+ transition:background .6s;
+}
+.ticker {
+ display:inline-block; white-space:nowrap;
+ animation:marquee 20s linear infinite;
+ font-family:'Space Mono',monospace; font-size:.75rem;
+ letter-spacing:.08em; color:var(--text-secondary); padding-left:7rem;
+}
+.ticker:hover { animation-play-state:paused; }
+
+.search-bar { margin-bottom:2rem; position:relative; display:flex; justify-content:center; }
+.search-bar::before {
+ content:'⌕'; position:absolute; left:calc(50% - 210px); top:50%;
+ transform:translateY(-50%); font-size:1.1rem; color:var(--text-muted);
+ pointer-events:none; z-index:1; transition:color .2s;
+}
+.search-bar:focus-within::before { color:var(--theme-color); }
+.search-bar input {
+ width:100%; max-width:460px; padding:.7rem 1.25rem .7rem 2.5rem;
+ background:rgba(255,255,255,.03); border:1px solid var(--border); border-radius:6px;
+ color:var(--text-primary); font-family:'Space Mono',monospace;
+ font-size:.8rem; letter-spacing:.05em; outline:none;
+ transition:border-color .2s, box-shadow .2s, background .2s;
+}
+.search-bar input::placeholder { color:var(--text-muted); }
+.search-bar input:focus {
+ border-color:var(--theme-color); background:var(--theme-subtle);
+ box-shadow:0 0 20px var(--theme-glow);
+}
+
+.table-container { margin-bottom:3rem; }
+.data-table { width:100%; max-width:1300px; margin:0 auto; border-collapse:collapse; font-size:.88rem; }
+.data-table thead tr { background:rgba(255,255,255,.03); }
+.data-table th {
+ padding:.85rem 1.1rem; text-align:center;
+ font-family:'Space Mono',monospace; font-size:.65rem; font-weight:700;
+ letter-spacing:.2em; text-transform:uppercase; color:var(--theme-color);
+ border-bottom:1px solid var(--theme-color); border-right:1px solid var(--border);
+ position:relative; transition:color .6s, border-color .6s;
+}
+.data-table th::after {
+ content:''; position:absolute; bottom:-1px; left:0; right:0; height:2px;
+ background:var(--theme-color); transform:scaleX(0); transition:transform .3s;
+ box-shadow:0 0 8px var(--theme-glow);
+}
+.data-table th:hover::after { transform:scaleX(1); }
+.data-table th:last-child, .data-table td:last-child { border-right:none; }
+.data-table td {
+ padding:.85rem 1.1rem; border-bottom:1px solid var(--border);
+ border-right:1px solid var(--border); color:var(--text-secondary);
+ transition:all .2s ease; vertical-align:middle;
+}
+.data-table tbody tr { transition:background .2s; animation:rowFadeIn .4s both; }
+.data-table tbody tr:nth-child(1) { animation-delay:.05s; }
+.data-table tbody tr:nth-child(2) { animation-delay:.10s; }
+.data-table tbody tr:nth-child(3) { animation-delay:.15s; }
+.data-table tbody tr:nth-child(4) { animation-delay:.20s; }
+.data-table tbody tr:nth-child(5) { animation-delay:.25s; }
+.data-table tbody tr:nth-child(6) { animation-delay:.30s; }
+.data-table tbody tr:nth-child(7) { animation-delay:.35s; }
+.data-table tbody tr:nth-child(8) { animation-delay:.40s; }
+.data-table tbody tr:nth-child(9) { animation-delay:.45s; }
+.data-table tbody tr:nth-child(10) { animation-delay:.50s; }
+.data-table tbody tr:hover td { background:var(--theme-subtle); color:var(--text-primary); }
+.data-table tbody tr:hover td:first-child { border-left:2px solid var(--theme-color); padding-left:calc(1.1rem - 2px); }
+.col-desc { width:40%; min-width:280px; text-align:left !important; font-size:.85rem; line-height:1.55; }
+.col-url { width:15%; max-width:320px; word-break:break-all; font-family:'Space Mono',monospace; font-size:.72rem; }
+.col-url a { color:var(--theme-color) !important; text-decoration:none !important; opacity:.85; transition:opacity .2s, text-shadow .2s; }
+.col-url a:hover { opacity:1; text-shadow:0 0 10px var(--theme-glow); text-decoration:underline !important; }
+.hidden-row { display:none !important; }
+
+.show-more-btn {
+ display:inline-flex; align-items:center; gap:.5rem;
+ margin:1.5rem auto 0; padding:.6rem 1.75rem;
+ background:transparent; color:var(--theme-color);
+ border:1px solid var(--theme-color); border-radius:4px; cursor:pointer;
+ font-family:'Space Mono',monospace; font-size:.75rem;
+ letter-spacing:.15em; text-transform:uppercase;
+ position:relative; overflow:hidden; transition:all .25s ease;
+}
+.show-more-btn::before {
+ content:''; position:absolute; inset:0;
+ background:var(--theme-subtle); transform:scaleX(0); transform-origin:left; transition:transform .3s;
+}
+.show-more-btn:hover::before { transform:scaleX(1); }
+.show-more-btn:hover { box-shadow:0 0 24px var(--theme-glow); transform:translateY(1px); }
+
+.site-footer {
+ text-align:center; padding:1.25rem 2rem;
+ background:rgba(2,4,8,.7); backdrop-filter:blur(10px);
+ color:var(--text-muted); font-family:'Space Mono',monospace;
+ font-size:.7rem; letter-spacing:.15em;
+ border-top:1px solid var(--border);
+ cursor:pointer; user-select:none;
+ transition:border-color .6s, background .2s;
+}
+.site-footer::before { content:'◈ '; color:var(--theme-color); transition:color .6s; }
+.site-footer:hover { background:rgba(255,255,255,.03); }
+.footer-credits-hint { opacity:.5; font-style:italic; transition:opacity .2s; }
+.site-footer:hover .footer-credits-hint { opacity:1; color:var(--theme-color); }
+
+.daily-challenge-box {
+ margin:0 auto 2rem; max-width:680px; padding:1rem 1.5rem;
+ background:var(--theme-subtle); border:1px solid var(--border);
+ border-left:3px solid var(--theme-color); border-radius:8px; text-align:left;
+}
+.daily-challenge-title {
+ display:block; font-family:'Orbitron',monospace; font-size:.7rem; font-weight:700;
+ letter-spacing:.25em; text-transform:uppercase;
+ color:var(--theme-color); text-shadow:0 0 12px var(--theme-glow); margin-bottom:.5rem;
+}
+.daily-challenge-desc { font-size:.85rem; line-height:1.6; color:var(--text-secondary); }
+
+#quiz-container {
+ margin:0 auto 3rem; max-width:680px; padding:2.25rem 2.5rem;
+ background:rgba(255,255,255,.02); border:1px solid var(--border); border-radius:12px;
+ text-align:center; position:relative; overflow:hidden;
+ box-shadow:0 0 40px var(--theme-glow), inset 0 0 60px rgba(0,0,0,.3);
+ display:flex; flex-direction:column; min-height:400px;
+}
+#quiz-container::before {
+ content:''; position:absolute; top:0; left:0; right:0; height:2px;
+ background:linear-gradient(90deg,transparent,var(--theme-color),transparent);
+}
+#quiz-question {
+ font-size:.95rem; font-weight:500; line-height:1.6;
+ color:var(--text-primary); margin-bottom:1.5rem;
+ white-space:pre-line; text-align:left; flex-grow:1;
+ display:flex; align-items:center; min-height:120px;
+}
+#quiz-options { display:grid; grid-template-columns:1fr 1fr; gap:.75rem; margin-bottom:1rem; width:100%; }
+
+.quiz-btn {
+ background:rgba(255,255,255,.03); color:var(--text-primary);
+ border:1px solid var(--border); border-radius:8px; padding:.9rem 1.1rem;
+ font-family:'Space Grotesk',sans-serif; font-size:.9rem; font-weight:500;
+ cursor:pointer; text-align:left; position:relative; overflow:hidden;
+ transition:all .2s ease;
+ display:flex; align-items:center; min-height:54px;
+}
+.quiz-btn::before {
+ content:''; position:absolute; inset:0;
+ background:var(--theme-subtle); opacity:0; transition:opacity .2s;
+}
+.quiz-btn:hover:not(:disabled) {
+ border-color:var(--theme-color); box-shadow:0 0 16px var(--theme-glow); transform:translateY(-1px);
+}
+.quiz-btn:hover:not(:disabled)::before { opacity:1; }
+.quiz-btn.correct {
+ background:rgba(74,222,128,.15) !important; border-color:#4ade80 !important;
+ color:#86efac !important; box-shadow:0 0 20px rgba(74,222,128,.3) !important;
+ animation:correctPulse .35s ease forwards;
+}
+.quiz-btn.correct::after { content:'✓'; position:absolute; right:1rem; top:50%; transform:translateY(-50%); color:#4ade80; pointer-events:none; }
+.quiz-btn.wrong {
+ background:rgba(248,113,113,.15) !important; border-color:#f87171 !important;
+ color:#fca5a5 !important; box-shadow:0 0 20px rgba(248,113,113,.25) !important;
+ animation:shake .3s ease forwards;
+}
+.quiz-btn.wrong::after { content:'✗'; position:absolute; right:1rem; top:50%; transform:translateY(-50%); color:#f87171; pointer-events:none; }
+
+#quiz-score {
+ margin-top:1.5rem; font-family:'Orbitron',monospace; font-size:1.1rem; font-weight:700;
+ letter-spacing:.1em; color:var(--theme-color); text-shadow:0 0 20px var(--theme-glow);
+}
+#quiz-restart-btn {
+ display:none; margin-top:1.25rem; padding:.65rem 2rem;
+ background:transparent; color:var(--theme-color);
+ border:1px solid var(--theme-color); border-radius:6px; cursor:pointer;
+ font-family:'Space Mono',monospace; font-size:.75rem;
+ letter-spacing:.15em; text-transform:uppercase; transition:all .25s;
+}
+#quiz-restart-btn:hover { background:var(--theme-subtle); box-shadow:0 0 20px var(--theme-glow); transform:translateY(-1px); }
+
+#quiz-img-preview {
+ max-width:640px; margin:1.5rem auto 0;
+ border:1px solid var(--border); border-radius:10px; overflow:hidden;
+ background:rgba(0,0,0,.3); opacity:0; max-height:0; text-align:left;
+ transition:opacity .5s, max-height .5s, border-color .6s;
+}
+#quiz-img-preview.visible { opacity:1; max-height:480px; }
+.quiz-img-label {
+ padding:.5rem 1rem; font-family:'Space Mono',monospace; font-size:.6rem;
+ letter-spacing:.2em; color:var(--theme-color);
+ border-bottom:1px solid var(--border); background:rgba(255,255,255,.02);
+}
+#quiz-img-preview img, #quiz-img-preview video {
+ display:block; width:100%; max-height:320px; background:#000;
+}
+#quiz-img-preview img { object-fit:contain; }
+#quiz-img-preview video { outline:none; }
+#quiz-img-preview img[src=""], #quiz-img-preview video[src=""] { display:none; }
+.quiz-img-caption {
+ padding:.5rem 1rem; font-family:'Space Mono',monospace; font-size:.65rem;
+ color:var(--text-muted); word-break:break-all; border-top:1px solid var(--border);
+ white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
+}
+
+#credits-overlay {
+ position:fixed; inset:0; z-index:2000;
+ background:rgba(0,0,0,.7); backdrop-filter:blur(6px);
+ opacity:0; pointer-events:none; transition:opacity .35s;
+}
+#credits-overlay.open { opacity:1; pointer-events:all; }
+
+#credits-panel {
+ position:fixed; top:0; right:-480px; z-index:2001;
+ width:min(460px,95vw); height:100vh;
+ background:rgba(4,8,18,.97); backdrop-filter:blur(24px);
+ border-left:1px solid var(--border);
+ display:flex; flex-direction:column;
+ transition:right .4s cubic-bezier(.4,0,.2,1), border-color .6s;
+ overflow:hidden;
+}
+#credits-panel::before {
+ content:''; position:absolute; top:0; left:0; bottom:0; width:2px;
+ background:linear-gradient(180deg,transparent,var(--theme-color),transparent);
+ opacity:.6;
+}
+#credits-panel.open { right:0; }
+
+.credits-close {
+ position:absolute; top:1rem; right:1rem;
+ background:transparent; border:1px solid var(--border); border-radius:6px;
+ color:var(--text-muted); width:32px; height:32px; font-size:.8rem; cursor:pointer;
+ display:flex; align-items:center; justify-content:center;
+ transition:all .2s; z-index:1;
+}
+.credits-close:hover { border-color:var(--theme-color); color:var(--theme-color); box-shadow:0 0 10px var(--theme-glow); }
+
+.credits-header { padding:2.5rem 2rem 1.5rem; border-bottom:1px solid var(--border); flex-shrink:0; }
+.credits-tag {
+ display:block; font-family:'Space Mono',monospace; font-size:.6rem;
+ letter-spacing:.25em; color:var(--theme-color); margin-bottom:.75rem;
+ text-shadow:0 0 10px var(--theme-glow);
+}
+.credits-title {
+ font-family:'Orbitron',monospace; font-size:1.4rem; font-weight:900;
+ letter-spacing:.1em; color:var(--text-primary);
+ text-shadow:0 0 30px var(--theme-glow); margin-bottom:.25rem;
+}
+.credits-version { font-family:'Space Mono',monospace; font-size:.7rem; color:var(--text-muted); letter-spacing:.1em; }
+
+.credits-body { flex:1; overflow-y:auto; padding:1.5rem 2rem; scrollbar-width:thin; scrollbar-color:var(--theme-color) transparent; }
+.credits-section { margin-bottom:2rem; }
+.credits-section h3 {
+ font-family:'Space Mono',monospace; font-size:.65rem; font-weight:700;
+ letter-spacing:.2em; text-transform:uppercase; color:var(--theme-color);
+ margin-bottom:.75rem; padding-bottom:.4rem; border-bottom:1px solid var(--border);
+}
+.credits-section p { font-size:.88rem; line-height:1.7; color:var(--text-secondary); }
+.credits-section ul { list-style:none; display:flex; flex-direction:column; gap:.4rem; }
+.credits-section ul li {
+ font-size:.85rem; color:var(--text-secondary); padding:.35rem .6rem;
+ border-left:1px solid var(--border); transition:border-color .2s, background .2s;
+}
+.credits-section ul li:hover { border-left-color:var(--theme-color); background:var(--theme-subtle); }
+.credits-section ul li span { font-family:'Space Mono',monospace; font-size:.75rem; color:var(--theme-color); margin-right:.5rem; text-shadow:0 0 8px var(--theme-glow); }
+
+.credits-footer { padding:1rem 2rem; border-top:1px solid var(--border); font-family:'Space Mono',monospace; font-size:.62rem; letter-spacing:.15em; color:var(--text-muted); flex-shrink:0; }
+
+::-webkit-scrollbar { width:6px; }
+::-webkit-scrollbar-track { background:var(--bg-deep); }
+::-webkit-scrollbar-thumb { background:var(--theme-color); border-radius:3px; }
+::selection { background:var(--theme-glow); color:#fff; }
+
+@keyframes layerReveal {
+ from { opacity:0; transform:translateY(16px); filter:blur(4px); }
+ to { opacity:1; transform:translateY(0); filter:blur(0); }
+}
+@keyframes rowFadeIn {
+ from { opacity:0; transform:translateX(-8px); }
+ to { opacity:1; transform:translateX(0); }
+}
+@keyframes marquee {
+ from { transform:translateX(100vw); }
+ to { transform:translateX(-100%); }
+}
+@keyframes glitch {
+ 0%,30%,50%,100% { text-shadow:0 0 20px var(--theme-glow); transform:translate(0); }
+ 10% { text-shadow:-2px 0 var(--theme-color),2px 0 rgba(255,0,100,.6); transform:translate(-1px,0); }
+ 20% { text-shadow:2px 0 var(--theme-color),-2px 0 rgba(0,200,255,.6); transform:translate(1px,0); }
+ 40% { text-shadow:-3px 0 rgba(255,0,100,.5),3px 0 var(--theme-color); transform:translate(2px,-1px); }
+ 60% { text-shadow:2px 0 rgba(0,200,255,.6),-1px 0 var(--theme-color); transform:translate(-1px,1px); }
+}
+@keyframes correctPulse {
+ 0%,100% { transform:scale(1); }
+ 40% { transform:scale(1.025); }
+}
+@keyframes shake {
+ 0%,100% { transform:translateX(0); }
+ 25% { transform:translateX(-5px); }
+ 50% { transform:translateX(5px); }
+ 75% { transform:translateX(-3px); }
+}
+@media (max-width:768px) {
+ #layer-Quiz .desc-box, #layer-Quiz .daily-challenge-box { display:none; }
+}
+@media (max-width:520px) {
+ header { padding:0 1rem; }
+ header h1 { font-size:.85rem; letter-spacing:.05em; text-align:center; }
+ .menu-icon, .help-btn { padding:.4rem .6rem; font-size:.7rem; }
+ #content-area { padding:1.5rem 1rem; }
+ .flex-row .box { min-width:100%; }
+ .desc-box { padding:1.25rem 1rem; font-size:.85rem; }
+ #quiz-options { grid-template-columns:1fr; gap:0.6rem; }
+ #quiz-container { padding:1.25rem 1rem; height:auto; min-height:auto; justify-content:center; overflow:visible; margin-bottom:1rem; }
+ #quiz-question { min-height:auto; font-size:.88rem; align-items:center; justify-content:center; text-align:center; margin-top:0; margin-bottom:1rem; }
+ .quiz-btn { min-height:44px; font-size:.8rem; padding:.6rem .75rem; justify-content:center; text-align:center; }
+ #quiz-img-preview.visible { max-height:none; margin-bottom:1rem; text-align:center; }
+ #quiz-img-preview img, #quiz-img-preview video { max-height:160px; width:auto; max-width:100%; margin:0 auto; }
+}
+
+body.page-form { background-color: #0f172a; color: #e0e0e0; display: flex; flex-direction: row; justify-content: center; align-items: center; padding: 2rem; min-height: 100vh; overflow-x: auto; }
+.admin-box { background-color: #1e293b; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 15px rgba(0,0,0,0.5); width: 100%; max-width: 500px; border: 1px solid #334155; }
+.admin-box h1 { color: #00bfff; text-align: center; margin-bottom: 1.5rem; }
+.form-group { margin-bottom: 1rem; }
+.form-group label { display: block; margin-bottom: 0.5rem; color: #b9bbbe; font-size: 0.9rem; }
+.form-group input, .form-group select, .form-group textarea { width: 100%; padding: 0.75rem; background: #0f172a; border: 1px solid #334155; border-radius: 4px; color: white; font-family: inherit; }
+.btn-submit { width: 100%; padding: 0.75rem; background-color: #00bfff; color: white; border: none; border-radius: 4px; font-weight: 600; cursor: pointer; margin-top: 1rem; transition: background 0.2s; }
+.btn-submit:hover { background-color: #009acd; }
+.links { text-align: center; margin-top: 1.5rem; display: flex; flex-direction: column; gap: 0.5rem; }
+.links a { color: #94a3b8; text-decoration: none; font-size: 0.9rem; transition: color 0.2s; }
+.links a:hover { color: #ffffff; }
+input[type="file"] { cursor: pointer; padding: 0.6rem; }
+input[type="file"]::file-selector-button { background: #334155; color: white; border: none; padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; margin-right: 1rem; transition: background 0.2s; }
+input[type="file"]::file-selector-button:hover { background: #475569; }
+
+/* Correction absolue pour App Mobile Native (Capacitor) */
+body.is-mobile-app #safe-area-block { height: max(env(safe-area-inset-top), 45px); }
+body.is-mobile-app header { top: max(env(safe-area-inset-top), 45px); }
+body.is-mobile-app .sidebar { padding-top: calc(5rem + max(env(safe-area-inset-top), 45px)); }
+body.is-mobile-app .sidebar::before { top: calc(1.5rem + max(env(safe-area-inset-top), 45px)); }
+body.is-mobile-app .credits-close { top: calc(1rem + max(env(safe-area-inset-top), 45px)); }
\ No newline at end of file
diff --git a/3ds/source/main.cpp b/3ds/source/main.cpp
new file mode 100644
index 0000000..3600c8f
--- /dev/null
+++ b/3ds/source/main.cpp
@@ -0,0 +1,92 @@
+// 3ds/source/main.cpp
+#include <3ds.h>
+#include
+#include
+#include
+
+// Définition des couleurs pour plus de clarté (Format: RGBA)
+#define CLR_BG C2D_Color32(0x06, 0x0d, 0x18, 0xFF) // #060d18
+#define CLR_TEXT C2D_Color32(0xe8, 0xf0, 0xff, 0xFF) // #e8f0ff
+#define CLR_PRIMARY C2D_Color32(0x4f, 0x8e, 0xff, 0xFF) // #4f8eff
+
+// Fonction pour lire un fichier depuis le romfs
+char* readFile(const char* path) {
+ FILE* file = fopen(path, "r");
+ if (!file) {
+ return NULL;
+ }
+
+ fseek(file, 0, SEEK_END);
+ long size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ char* buffer = (char*)malloc(size + 1);
+ if (!buffer) {
+ fclose(file);
+ return NULL;
+ }
+
+ fread(buffer, 1, size, file);
+ buffer[size] = '\0';
+ fclose(file);
+ return buffer;
+}
+
+int main(int argc, char* argv[]) {
+ // --- Initialisation ---
+ romfsInit();
+ gfxInitDefault();
+ C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
+ C2D_Init(C2D_DEFAULT_MAX_OBJECTS);
+ C2D_Prepare();
+
+ // Crée un "canevas" pour l'écran supérieur
+ C3D_RenderTarget* top = C2D_CreateScreenTarget(GFX_TOP, GFX_LEFT);
+
+ // Prépare un buffer pour le texte
+ C2D_TextBuf textBuf = C2D_TextBufNew(4096);
+ C2D_Text text;
+
+ // Lecture du fichier main.js
+ char* js_content = readFile("romfs:/main.js");
+
+ // --- Boucle principale de l'application ---
+ while (aptMainLoop()) {
+ hidScanInput();
+ u32 kDown = hidKeysDown();
+
+ if (kDown & KEY_START) {
+ free(js_content); // Libère la mémoire avant de quitter
+ break; // Quitte l'application
+ }
+
+ // --- Phase de dessin ---
+ C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
+
+ // Dessin sur l'écran du haut
+ C2D_TargetClear(top, CLR_BG);
+ C2D_SceneBegin(top);
+
+ // Dessine du texte
+ C2D_TextBufClear(textBuf);
+ C2D_TextParse(&text, textBuf, "Lecture de romfs:/main.js reussie !");
+ C2D_TextOptimize(&text);
+ C2D_DrawText(&text, C2D_WithColor, 20.0f, 20.0f, 0.5f, 0.5f, 0.5f, CLR_PRIMARY);
+
+ if (js_content) {
+ C2D_TextParse(&text, textBuf, js_content);
+ C2D_TextOptimize(&text);
+ C2D_DrawText(&text, C2D_WithColor, 20.0f, 50.0f, 0.5f, 0.4f, 0.4f, CLR_TEXT);
+ }
+
+ C3D_FrameEnd(0);
+ }
+
+ // --- Libération des ressources ---
+ C2D_TextBufDelete(textBuf);
+ C2D_Fini();
+ C3D_Fini();
+ romfsExit();
+ gfxExit();
+ return 0;
+}
diff --git a/c_cpp_properties.json b/c_cpp_properties.json
new file mode 100644
index 0000000..f2efac5
--- /dev/null
+++ b/c_cpp_properties.json
@@ -0,0 +1,20 @@
+{
+ "configurations": [
+ {
+ "name": "3DS DevkitARM",
+ "includePath": [
+ "${workspaceFolder}/**",
+ "C:/devkitPro/libctru/include", // Chemin Windows standard
+ "/opt/devkitpro/libctru/include" // Chemin Linux/macOS standard
+ ],
+ "defines": [
+ "__3DS__"
+ ],
+ "compilerPath": "C:/devkitPro/devkitARM/bin/arm-none-eabi-g++.exe", // Aide l'intellisense
+ "cStandard": "c11",
+ "cppStandard": "c++11",
+ "intelliSenseMode": "windows-gcc-arm"
+ }
+ ],
+ "version": 4
+}
\ No newline at end of file