Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec800d28ae | ||
|
|
80786cb040 | ||
|
|
67857b9bfd | ||
|
|
cedda338df | ||
|
|
bfe7f3576a | ||
|
|
6b21b45e01 | ||
|
|
aeaeed6867 | ||
|
|
72b7d51af9 | ||
|
|
bd5d7f0028 | ||
|
|
b6334035fc | ||
|
|
7626852ac1 | ||
|
|
754ff9436c | ||
|
|
0367f07166 | ||
|
|
c45ddc779c | ||
|
|
5b7170e5f4 | ||
|
|
cbebc1a6f7 | ||
|
|
8ed7796968 | ||
|
|
5d4d167cbd | ||
|
|
6c8688c9f6 | ||
|
|
54ba08cdbc | ||
|
|
777e0ffddb | ||
|
|
76f7ff3a46 | ||
|
|
b3c0994b7e | ||
|
|
fb361a2854 | ||
|
|
a2934f1327 | ||
|
|
558d0e5ecd | ||
|
|
6aba40e128 | ||
|
|
f6d9992a2c | ||
|
|
3e7fdf5dfc | ||
|
|
85ff73774c | ||
|
|
e5e7d80050 | ||
|
|
8c2f388c7f | ||
|
|
1bbe41b6fc | ||
|
|
fde51856ce | ||
|
|
8935f31091 | ||
|
|
81156284ac | ||
|
|
7dd46de5d9 | ||
|
|
7d8e9f596c | ||
|
|
ef0a55db77 | ||
|
|
ceb5f89320 | ||
|
|
a18afde2db | ||
|
|
38563e2142 | ||
|
|
aeb0adada9 | ||
|
|
e58dacd98c | ||
|
|
edc9225ccf | ||
|
|
5b94593d94 | ||
|
|
3bd6d7b459 | ||
|
|
c57db78c52 | ||
|
|
c1277cc737 | ||
|
|
fd8b107643 | ||
|
|
3a2e1a8d15 | ||
|
|
ac89d69365 | ||
|
|
552949811e | ||
|
|
030bb322a2 | ||
|
|
9631a1c45b | ||
|
|
4245ea2567 | ||
|
|
51146d3dfc | ||
|
|
fda4aca4c7 | ||
|
|
aff352fa91 | ||
|
|
ea7e905c61 | ||
|
|
512fbd9d3d | ||
|
|
f9185d25e0 | ||
|
|
4f3b680951 | ||
|
|
a2b1c0484a | ||
|
|
1480d31a54 | ||
|
|
514896db33 | ||
|
|
b21e2394d5 | ||
|
|
7da018d92c | ||
|
|
9e12447528 |
No files matched your search
@@ -2,6 +2,7 @@
|
||||
build/
|
||||
*.pdf
|
||||
*.html
|
||||
!slides/*/assets/demos/**/*.html
|
||||
.dev-index/
|
||||
|
||||
# Dependencies
|
||||
|
||||
@@ -0,0 +1,197 @@
|
||||
# AGENTS.md - Agent Guidelines for HdM Slides
|
||||
|
||||
This file contains comprehensive guidelines for agentic coding agents working on the HdM Slides project.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This project builds presentation decks for Marp, supporting multiple courses:
|
||||
- **223015b** - Dateiformate, Schnittstellen, Speichermedien (6 Kapitel)
|
||||
- **223015c** - Internettechnologien (3 Kapitel)
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Build Commands
|
||||
```bash
|
||||
# Development
|
||||
make dev # Start single dev server on port 3000
|
||||
npm run dev # Alternative command for development server
|
||||
|
||||
# Build
|
||||
make build # Build all courses (HTML + PDF)
|
||||
make build-b # Build 223015b only
|
||||
make build-c # Build 223015c only
|
||||
make html # HTML only builds
|
||||
make pdf # PDF only builds
|
||||
|
||||
# Klausur Folien
|
||||
make klausur # Extract klausurfolien for all courses
|
||||
make klausur-b # Extract klausurfolien for 223015b
|
||||
make klausur-c # Extract klausurfolien for 223015c
|
||||
|
||||
# Deployment
|
||||
make deploy # Deploy all courses (requires explicit permission)
|
||||
make deploy-b # Deploy 223015b only
|
||||
make deploy-c # Deploy 223015c only
|
||||
|
||||
# Utilities
|
||||
make qr URL=... # Generate QR code
|
||||
make optimize-images COURSE=223015b # Resize images
|
||||
make clean # Remove generated files
|
||||
```
|
||||
|
||||
### Testing
|
||||
No specific test framework is used. To validate changes:
|
||||
1. Start dev server: `make dev`
|
||||
2. Open http://localhost:3000/223015b/ or /223015c/
|
||||
3. Verify slides render correctly
|
||||
4. Run `make build` to ensure no build errors
|
||||
5. Check generated files in `build/` directory
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### File Structure
|
||||
- Slides in `slides/<course>/` following naming pattern `NN-topic.md`
|
||||
- Assets in `slides/<course>/assets/`
|
||||
- Always reference images as `./assets/filename.png`
|
||||
- Scripts in `scripts/`
|
||||
- Themes in `themes/`
|
||||
- Generated output in `build/` (gitignored)
|
||||
|
||||
### Naming Conventions
|
||||
- Slide files: `NN-topic.md` (e.g., `01-grundlagen.md`, `02-bilder.md`)
|
||||
- Images: `snake_case.jpg` or `kebab-case.jpg`
|
||||
- Klausur files: `klausurfolien.md` (auto-generated)
|
||||
- Function names in scripts: `snake_case`
|
||||
- Variable names in scripts: `snake_case`
|
||||
|
||||
### Markdown Style
|
||||
- Use ATX-style headers (`# ## ###`)
|
||||
- YAML frontmatter for slide metadata at top of each file
|
||||
- Never include a final `---` (creates empty slide)
|
||||
- Use `<!-- _class: klausur -->` for exam-relevant slides
|
||||
- Use relative paths for assets: `./assets/image.png`
|
||||
|
||||
### Script Style
|
||||
- Use `#!/usr/bin/env bash` shebang
|
||||
- Use `set -e` for error handling
|
||||
- Use `2>/dev/null || true` for optional operations
|
||||
- Define variables in UPPER_CASE at script top
|
||||
- Use colors for terminal output: `\033[0;32m` etc.
|
||||
|
||||
### Git Workflow
|
||||
- Commit messages: ALWAYS lowercase
|
||||
- NEVER add co-authoring lines or generated footers
|
||||
- Follow semantic naming: "add-...", "fix-...", "update-..."
|
||||
- Commit changes to scripts, Makefile, documentation separately from slide content
|
||||
|
||||
## Agent Restrictions
|
||||
|
||||
### Security
|
||||
- NEVER run commands outside `/home/mwc/Coding/hdm` folder
|
||||
- NEVER run build/deploy commands without explicit user request
|
||||
- NEVER run deploy commands (make deploy, scp, etc.) without explicit permission
|
||||
|
||||
### File Protection
|
||||
Slide files in `slides/*/*.md` are main content files:
|
||||
- **ALLOWED**: Adding slides, adjusting content, fixing typos, enhancing sections
|
||||
- **FORBIDDEN** (without permission): Deleting slides, removing sections, bulk deletions
|
||||
- Before ANY deletion: ALWAYS ask user for confirmation
|
||||
|
||||
### Klausur Handling
|
||||
- Klausur files (`klausurfolien.md`) are auto-generated
|
||||
- NEVER edit klausurfolien.md files directly
|
||||
- To update klausurfolien: edit source slides with `<!-- _class: klausur -->` markers
|
||||
- Run `make klausur` to regenerate
|
||||
|
||||
## Development Patterns
|
||||
|
||||
### Adding New Slides
|
||||
1. Create new file following `NN-topic.md` pattern
|
||||
2. Copy frontmatter from existing slides in the same course
|
||||
3. Update Makefile `_KAPITEL` variable if needed
|
||||
4. Test with `make dev`
|
||||
|
||||
### Modifying Existing Slides
|
||||
1. Edit the appropriate markdown file in `slides/<course>/`
|
||||
2. Maintain consistent styling with course theme
|
||||
3. Preserve image paths as `./assets/...`
|
||||
4. Test changes with dev server
|
||||
|
||||
### Working with Assets
|
||||
1. Place images in `slides/<course>/assets/`
|
||||
2. Use descriptive names: `diagram-network.jpg`, `example-code.png`
|
||||
3. Optimize with `make optimize-images COURSE=223015b`
|
||||
4. Reference as `./assets/filename.ext`
|
||||
|
||||
### Course-Specific Configuration
|
||||
Each course has specific settings in Makefile:
|
||||
- Course name and title
|
||||
- Kapitel list (slide files)
|
||||
- Deploy path
|
||||
- Theme colors (in generate-index.sh)
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Debugging Build Issues
|
||||
1. Check Makefile syntax: `make -n build`
|
||||
2. Verify Marp CLI installation: `npx @marp-team/marp-cli --version`
|
||||
3. Check file permissions: `ls -la slides/`
|
||||
4. Validate markdown syntax with dev server
|
||||
|
||||
### Updating Course Structure
|
||||
1. Update `_KAPITEL` variables in Makefile
|
||||
2. Ensure slide files follow naming convention
|
||||
3. Update course-specific themes if needed
|
||||
4. Test both dev and build processes
|
||||
|
||||
### Working with Themes
|
||||
- Custom theme in `themes/custom-theme.css`
|
||||
- Course themes defined in individual slide frontmatter
|
||||
- Use consistent color schemes per course
|
||||
- Test theme changes across all slides
|
||||
|
||||
## Deployment Process
|
||||
|
||||
Deployment to production server requires explicit permission:
|
||||
1. Build process: `make build` (HTML + PDF)
|
||||
2. Index generation: automatically handled
|
||||
3. Deploy to remote server via SCP
|
||||
4. Root index deployment
|
||||
|
||||
**IMPORTANT**: Never run deployment commands without explicit user permission.
|
||||
|
||||
## Tools and Dependencies
|
||||
|
||||
### Core Dependencies
|
||||
- Marp CLI for slide rendering
|
||||
- Bash scripts for automation
|
||||
- Make for build orchestration
|
||||
- Git for version control
|
||||
|
||||
### Optional Tools
|
||||
- qrencode for QR generation (via nix)
|
||||
- ImageMagick for image optimization
|
||||
- Python 3 for simple HTTP server (legacy)
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
Since there's no formal test suite:
|
||||
1. Manual testing with dev server
|
||||
2. Build process validation
|
||||
3. Slide rendering checks
|
||||
4. Asset path verification
|
||||
5. Cross-browser compatibility checks (important)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
- **Port conflicts**: Use `make dev-kill` to clean up processes
|
||||
- **Build failures**: Check file permissions and Marp CLI installation
|
||||
- **Asset loading**: Verify relative paths and file existence
|
||||
- **Deploy issues**: Check SSH keys and remote permissions
|
||||
|
||||
### Getting Help
|
||||
1. Check this AGENTS.md file first
|
||||
2. Review Makefile targets and scripts
|
||||
3. Test changes incrementally
|
||||
4. Maintain backup of working configurations
|
||||
@@ -12,6 +12,7 @@ This project builds presentation decks for Marp, supporting multiple courses.
|
||||
- Agent NEVER runs commands outside this folder
|
||||
- Agent NEVER runs build/deploy commands without explicit user request
|
||||
- Agent NEVER runs deploy commands (make deploy, scp, etc.) without explicit user permission
|
||||
- Agent NEVER runs `git checkout --` or `git restore` on files with uncommitted work. To undo specific changes, use targeted Edit operations instead.
|
||||
|
||||
## Critical File Protection
|
||||
|
||||
@@ -34,8 +35,9 @@ build/ # Generated output (gitignored)
|
||||
## Build Commands
|
||||
|
||||
```bash
|
||||
make dev-b # Dev server 223015b (port 1311)
|
||||
make dev-c # Dev server 223015c (port 1312)
|
||||
make dev # Marp live server all courses (port 1312, HMR)
|
||||
make dev-b # Marp live server 223015b (port 1313, HMR)
|
||||
make dev-c # Marp live server 223015c (port 1314, HMR)
|
||||
make build # Build all courses
|
||||
make build-b # Build 223015b only
|
||||
make build-c # Build 223015c only
|
||||
@@ -48,10 +50,7 @@ make deploy # Deploy all (ASK FIRST!)
|
||||
## Nix Flake Commands
|
||||
|
||||
```bash
|
||||
nix develop # Dev shell with all tools
|
||||
nix run .#qr -- "https://example.com" # Generate QR code
|
||||
nix run .#qr-slides -- 223015b # QR for course
|
||||
nix run .#optimize-img -- <path> # Optimize images
|
||||
nix develop # Dev shell with all tools (node 22, npm, make)
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
@@ -7,19 +7,13 @@
|
||||
COURSES = 223015b 223015c
|
||||
SLIDES_DIR = slides
|
||||
|
||||
# Port configuration (index starts at BASE_PORT, courses increment from there)
|
||||
BASE_PORT = 1310
|
||||
INDEX_PORT = $(BASE_PORT)
|
||||
|
||||
# Course-specific settings
|
||||
223015b_NAME = Dateiformate, Schnittstellen, Speichermedien
|
||||
223015b_PORT = 1311
|
||||
223015b_KAPITEL = 00-intro 01-grundlagen-text-audio 02-bild-audio-video 03-speichermedien-schnittstellen 04-distribution-apis-zukunft 05-vertiefung-offene-fragen klausur
|
||||
223015b_KAPITEL = 00-intro 01-grundlagen-text-audio 02-bild-audio-video 03-speichermedien-schnittstellen 04-distribution-apis-zukunft 05-vertiefung-offene-fragen klausurfolien klausurfragen
|
||||
223015b_DEPLOY_PATH = /home/tengo/html/hdm/223015b
|
||||
|
||||
223015c_NAME = Internettechnologien
|
||||
223015c_PORT = 1312
|
||||
223015c_KAPITEL = 01-geschichte-grundlagen-html 02-netzwerke-protokolle-css 03-interaktivitaet-javascript klausur
|
||||
223015c_KAPITEL = 01-geschichte-grundlagen-html 02-netzwerke-protokolle-css 03-interaktivitaet-javascript klausurfolien klausurfragen
|
||||
223015c_DEPLOY_PATH = /home/tengo/html/hdm/223015c
|
||||
|
||||
DEPLOY_HOST = tengo@tuttle.uberspace.de
|
||||
@@ -33,9 +27,9 @@ help:
|
||||
@echo " 223015c - Internettechnologien"
|
||||
@echo ""
|
||||
@echo "Development:"
|
||||
@echo " make dev - Both servers + index (ports 1311, 1312, 1313)"
|
||||
@echo " make dev-b - Dev server for 223015b (port 1312)"
|
||||
@echo " make dev-c - Dev server for 223015c (port 1313)"
|
||||
@echo " make dev - Marp live server all courses (port 1312, HMR)"
|
||||
@echo " make dev-b - Marp live server 223015b (port 1313, HMR)"
|
||||
@echo " make dev-c - Marp live server 223015c (port 1314, HMR)"
|
||||
@echo ""
|
||||
@echo "Build:"
|
||||
@echo " make build - Build all courses"
|
||||
@@ -43,7 +37,7 @@ help:
|
||||
@echo " make build-c - Build 223015c only"
|
||||
@echo " make pdf - Export all to PDF"
|
||||
@echo " make html - Export all to HTML"
|
||||
@echo " make klausur - Extract klausur slides"
|
||||
@echo " make klausur - Extract klausurfolien slides"
|
||||
@echo ""
|
||||
@echo "Tools:"
|
||||
@echo " make qr URL=... - Generate QR code for URL"
|
||||
@@ -63,24 +57,20 @@ build/.exists:
|
||||
@mkdir -p build/223015b build/223015c
|
||||
@touch $@
|
||||
|
||||
# Development servers
|
||||
# Development server (Marp live server with HMR)
|
||||
dev:
|
||||
@./scripts/dev-server.sh
|
||||
|
||||
dev-kill:
|
||||
@-pkill -f "python3 -m http.server" 2>/dev/null || true
|
||||
@-pkill -f "marp-cli.*--server" 2>/dev/null || true
|
||||
@sleep 0.5
|
||||
|
||||
dev-b:
|
||||
@echo "Starting 223015b dev server on port $(223015b_PORT)..."
|
||||
@echo "Open: http://localhost:$(223015b_PORT)"
|
||||
PORT=$(223015b_PORT) npx @marp-team/marp-cli --server $(SLIDES_DIR)/223015b/
|
||||
@./scripts/dev-server.sh 223015b 1313
|
||||
|
||||
dev-c:
|
||||
@echo "Starting 223015c dev server on port $(223015c_PORT)..."
|
||||
@echo "Open: http://localhost:$(223015c_PORT)"
|
||||
PORT=$(223015c_PORT) npx @marp-team/marp-cli --server $(SLIDES_DIR)/223015c/
|
||||
@./scripts/dev-server.sh 223015c 1314
|
||||
|
||||
dev-kill:
|
||||
@-fuser -k 1312/tcp 2>/dev/null || true
|
||||
@-fuser -k 1313/tcp 2>/dev/null || true
|
||||
@-fuser -k 1314/tcp 2>/dev/null || true
|
||||
|
||||
# Build functions
|
||||
define build_course
|
||||
@@ -158,7 +148,7 @@ klausur-c:
|
||||
@./scripts/extract-klausur.sh 223015c
|
||||
|
||||
klausur: klausur-b klausur-c
|
||||
@echo "Klausur slides extracted for all courses!"
|
||||
@echo "Klausurfolien slides extracted for all courses!"
|
||||
|
||||
# QR Code generation (uses nix-shell)
|
||||
qr:
|
||||
@@ -198,7 +188,8 @@ HDM_DEPLOY_PATH = /home/tengo/html/hdm
|
||||
|
||||
build-index: build/.exists
|
||||
@echo "Building root index..."
|
||||
@echo '<!DOCTYPE html><html lang="de"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>HdM Vorlesungen</title><style>*{box-sizing:border-box;margin:0;padding:0}body{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",Roboto,sans-serif;max-width:720px;margin:0 auto;padding:3rem 1.5rem;background:#fafafa;color:#1d1d1f;line-height:1.5}h1{font-size:2rem;font-weight:600;letter-spacing:-0.02em;margin-bottom:.5rem}.subtitle{color:#86868b;font-size:1rem}.courses{margin-top:2rem;display:flex;flex-direction:column;gap:.75rem}a.course{display:block;background:#fff;border-radius:12px;padding:1.5rem;text-decoration:none;color:inherit;box-shadow:0 1px 3px rgba(0,0,0,0.08);transition:all .2s ease;cursor:pointer}a.course:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,0.12)}.course-label{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}.course-b .course-label{color:#1e5f8a}.course-c .course-label{color:#d63384}.course-title{font-size:1.15rem;font-weight:500;color:#1d1d1f;margin:.25rem 0}.course-info{font-size:.85rem;color:#86868b}.section-title{font-size:1rem;font-weight:600;color:#86868b;margin-top:2.5rem;margin-bottom:.75rem}.references{display:flex;flex-direction:column;gap:.75rem}footer{margin-top:2.5rem;padding-top:1.5rem;border-top:1px solid #e5e5e7;color:#86868b;font-size:.85rem}footer a{color:#1d1d1f;text-decoration:none}footer a:hover{text-decoration:underline}.qr-section{margin-top:2.5rem;padding:1.5rem;background:#fff;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,0.08);text-align:center}.qr-code{width:100%;height:auto}.qr-url{margin-top:.75rem;font-size:.85rem;color:#86868b}</style></head><body><h1>HdM Vorlesungen</h1><p class="subtitle">Wintersemester 2025/26 · Michael Czechowski</p><div class="courses"><a class="course course-b" href="223015b/"><span class="course-label">223015b</span><div class="course-title">Dateiformate, Schnittstellen, Speichermedien & Distributionswege</div><span class="course-info">6 Kapitel · Modul "Technik 1"</span></a><a class="course course-c" href="223015c/"><span class="course-label">223015c</span><div class="course-title">Grundlagen IT- und Internettechnik</div><span class="course-info">3 Kapitel · Modul "Technik 1"</span></a></div><h2 class="section-title">Referenzen</h2><div class="references"><a class="course" href="https://codecrispi.es/"><span class="course-label">Plattform</span><div class="course-title">Code Crispies</div><span class="course-info">Selbstlernplattform</span></a></div><div class="qr-section"><img src="qr-root.svg" alt="QR Code" class="qr-code"><p class="qr-url">https://librete.ch/hdm/</p></div><footer><a href="mailto:mail@librete.ch">Kontakt</a></footer></body></html>' > build/index.html
|
||||
@mkdir -p build
|
||||
@./scripts/generate-root-index.sh
|
||||
|
||||
# Deploy
|
||||
define deploy_course
|
||||
|
||||
@@ -27,10 +27,12 @@ build/ # Generated output (gitignored)
|
||||
## Development
|
||||
|
||||
```bash
|
||||
# Start dev servers (hot reload)
|
||||
make dev # All courses + index
|
||||
make dev-b # 223015b only (port 1311)
|
||||
make dev-c # 223015c only (port 1312)
|
||||
# Start development server (hot reload)
|
||||
make dev # Single server for all courses (port 3000)
|
||||
|
||||
# Access individual courses:
|
||||
# 223015b: http://localhost:3000/223015b/
|
||||
# 223015c: http://localhost:3000/223015c/
|
||||
```
|
||||
|
||||
## Build
|
||||
@@ -43,7 +45,7 @@ make html # HTML only
|
||||
make pdf # PDF only
|
||||
```
|
||||
|
||||
## Klausur Slides
|
||||
## Klausur Folien
|
||||
|
||||
Extract exam-relevant slides (marked with `<!-- _class: klausur -->`) into a single file:
|
||||
|
||||
@@ -53,7 +55,7 @@ make klausur-b # 223015b only
|
||||
make klausur-c # 223015c only
|
||||
```
|
||||
|
||||
Output: `slides/<course>/klausur.md`
|
||||
Output: `slides/<course>/klausurfolien.md`
|
||||
|
||||
The generated file includes:
|
||||
- A title slide per kapitel for orientation
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
description = "HdM Slides - Marp presentation builder with tools";
|
||||
description = "HdM Slides - Marp presentation builder";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
@@ -9,114 +9,19 @@
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
|
||||
# QR code generator script
|
||||
qr-gen = pkgs.writeShellScriptBin "qr" ''
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: qr <url> [output.png]"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " qr https://example.com"
|
||||
echo " qr https://example.com my-qr.png"
|
||||
echo " qr 'https://librete.ch/hdm/223015b/' slides-qr.png"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
URL="$1"
|
||||
OUTPUT="''${2:-qr-code.png}"
|
||||
|
||||
${pkgs.qrencode}/bin/qrencode -o "$OUTPUT" -s 10 -m 2 "$URL"
|
||||
echo "Generated: $OUTPUT"
|
||||
'';
|
||||
|
||||
# QR code for course slides
|
||||
qr-slides = pkgs.writeShellScriptBin "qr-slides" ''
|
||||
COURSE="''${1:-223015b}"
|
||||
OUTPUT="''${2:-build/$COURSE/qr-$COURSE.png}"
|
||||
|
||||
mkdir -p "$(dirname "$OUTPUT")"
|
||||
${pkgs.qrencode}/bin/qrencode -o "$OUTPUT" -s 10 -m 2 "https://librete.ch/hdm/$COURSE/"
|
||||
echo "Generated QR for $COURSE: $OUTPUT"
|
||||
'';
|
||||
|
||||
# Image optimizer script
|
||||
optimize-img = pkgs.writeShellScriptBin "optimize-img" ''
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: optimize-img <image-or-directory> [max-width]"
|
||||
echo ""
|
||||
echo "Resizes images to max width (default: 1920px)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET="$1"
|
||||
MAX_WIDTH="''${2:-1920}"
|
||||
|
||||
if [ -d "$TARGET" ]; then
|
||||
for img in "$TARGET"/*.{png,jpg,jpeg,webp} 2>/dev/null; do
|
||||
[ -f "$img" ] || continue
|
||||
echo "Optimizing: $(basename "$img")"
|
||||
${pkgs.imagemagick}/bin/magick "$img" -resize "''${MAX_WIDTH}x>" -quality 85 "$img"
|
||||
done
|
||||
elif [ -f "$TARGET" ]; then
|
||||
echo "Optimizing: $TARGET"
|
||||
${pkgs.imagemagick}/bin/magick "$TARGET" -resize "''${MAX_WIDTH}x>" -quality 85 "$TARGET"
|
||||
else
|
||||
echo "Error: $TARGET not found"
|
||||
exit 1
|
||||
fi
|
||||
echo "Done!"
|
||||
'';
|
||||
|
||||
pkgs = import nixpkgs { inherit system; };
|
||||
in {
|
||||
# Development shell with all tools
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
nodejs_20
|
||||
nodejs_22
|
||||
nodePackages.npm
|
||||
qrencode
|
||||
imagemagick
|
||||
gnumake
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "HdM Slides Development Environment"
|
||||
echo ""
|
||||
echo "Available commands:"
|
||||
echo " make dev-b - Start 223015b dev server (port 1312)"
|
||||
echo " make dev-c - Start 223015c dev server (port 1313)"
|
||||
echo " make build - Build all courses"
|
||||
echo " qr <url> - Generate QR code"
|
||||
echo " qr-slides 223015b - Generate QR for course"
|
||||
echo " optimize-img <dir> - Optimize images"
|
||||
echo ""
|
||||
echo "HdM Slides - run 'make' for available commands"
|
||||
'';
|
||||
};
|
||||
|
||||
# Standalone apps
|
||||
packages = {
|
||||
qr = qr-gen;
|
||||
qr-slides = qr-slides;
|
||||
optimize-img = optimize-img;
|
||||
default = qr-gen;
|
||||
};
|
||||
|
||||
# Direct runnable apps
|
||||
apps = {
|
||||
qr = {
|
||||
type = "app";
|
||||
program = "${qr-gen}/bin/qr";
|
||||
};
|
||||
qr-slides = {
|
||||
type = "app";
|
||||
program = "${qr-slides}/bin/qr-slides";
|
||||
};
|
||||
optimize-img = {
|
||||
type = "app";
|
||||
program = "${optimize-img}/bin/optimize-img";
|
||||
};
|
||||
default = self.apps.${system}.qr;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -3,13 +3,14 @@
|
||||
"version": "1.0.0",
|
||||
"description": "HdM Stuttgart - Lecture Slides (Marp)",
|
||||
"scripts": {
|
||||
"dev:b": "PORT=1312 marp --server --allow-local-files courses/223015b/slides/",
|
||||
"dev:c": "PORT=1313 marp --server --allow-local-files courses/223015c/slides/",
|
||||
"dev": "PORT=3000 marp --server --allow-local-files slides/",
|
||||
"build": "make build",
|
||||
"build:b": "make build-b",
|
||||
"build:c": "make build-c",
|
||||
"pdf": "make pdf",
|
||||
"html": "make html",
|
||||
"klausur": "make klausur",
|
||||
"deploy": "make deploy",
|
||||
"test": "echo \"No tests specified\" && exit 0"
|
||||
},
|
||||
"keywords": ["marp", "slides", "hdm", "lectures"],
|
||||
|
||||
@@ -1,106 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
# Development server script for HdM slides
|
||||
# Starts index server + marp servers for each course
|
||||
# Development server for HdM slides
|
||||
# Usage:
|
||||
# ./dev-server.sh - Marp live server for all courses (port 1312)
|
||||
# ./dev-server.sh 223015b 1313 - Marp live server for single course
|
||||
# ./dev-server.sh 223015c 1314 - Marp live server for single course
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
INDEX_PORT=1310
|
||||
COURSE_B_PORT=1311
|
||||
COURSE_C_PORT=1312
|
||||
SLIDES_DIR="slides"
|
||||
DEV_INDEX_DIR=".dev-index"
|
||||
COURSE="${1:-}"
|
||||
DEV_PORT="${2:-1312}"
|
||||
|
||||
# Colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
echo -e "\n${RED}Shutting down servers...${NC}"
|
||||
kill $PID_INDEX $PID_B $PID_C 2>/dev/null || true
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Kill existing processes on our ports
|
||||
kill_existing() {
|
||||
echo -e "${BLUE}Cleaning up existing processes...${NC}"
|
||||
# Kill marp processes first
|
||||
pkill -9 -f "marp-cli" 2>/dev/null || true
|
||||
pkill -f "python3 -m http.server" 2>/dev/null || true
|
||||
# Kill ports including marp's WebSocket ports (37717-37720 range)
|
||||
fuser -k $INDEX_PORT/tcp $COURSE_B_PORT/tcp $COURSE_C_PORT/tcp 2>/dev/null || true
|
||||
fuser -k 37717/tcp 37718/tcp 37719/tcp 37720/tcp 2>/dev/null || true
|
||||
sleep 2
|
||||
}
|
||||
|
||||
# Generate dev index
|
||||
generate_index() {
|
||||
mkdir -p "$DEV_INDEX_DIR"
|
||||
cat > "$DEV_INDEX_DIR/index.html" << 'EOF'
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>HdM Slides - Dev</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",Roboto,sans-serif;max-width:720px;margin:0 auto;padding:3rem 1.5rem;background:#fafafa;color:#1d1d1f;line-height:1.5}
|
||||
h1{font-size:2rem;font-weight:600;letter-spacing:-0.02em;margin-bottom:.5rem}
|
||||
.subtitle{color:#86868b;font-size:1rem}
|
||||
.courses{margin-top:2rem;display:flex;flex-direction:column;gap:.75rem}
|
||||
a.course{display:block;background:#fff;border-radius:12px;padding:1.5rem;text-decoration:none;color:inherit;box-shadow:0 1px 3px rgba(0,0,0,0.08);transition:all .2s ease;cursor:pointer}
|
||||
a.course:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(0,0,0,0.12)}
|
||||
.course-label{font-size:.7rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em}
|
||||
.course-b .course-label{color:#1e5f8a}
|
||||
.course-c .course-label{color:#d63384}
|
||||
.course-title{font-size:1.15rem;font-weight:500;color:#1d1d1f;margin:.25rem 0}
|
||||
.course-info{font-size:.85rem;color:#86868b}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>HdM Slides</h1>
|
||||
<p class="subtitle">Development Server</p>
|
||||
<div class="courses">
|
||||
EOF
|
||||
echo " <a class=\"course course-b\" href=\"http://localhost:$COURSE_B_PORT\"><span class=\"course-label\">223015b</span><div class=\"course-title\">Dateiformate, Schnittstellen, Speichermedien & Distributionswege</div><span class=\"course-info\">Port $COURSE_B_PORT</span></a>" >> "$DEV_INDEX_DIR/index.html"
|
||||
echo " <a class=\"course course-c\" href=\"http://localhost:$COURSE_C_PORT\"><span class=\"course-label\">223015c</span><div class=\"course-title\">Grundlagen IT- und Internettechnik</div><span class=\"course-info\">Port $COURSE_C_PORT</span></a>" >> "$DEV_INDEX_DIR/index.html"
|
||||
cat >> "$DEV_INDEX_DIR/index.html" << 'EOF'
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
# Kill existing process on our port only
|
||||
kill_port() {
|
||||
fuser -k "$DEV_PORT/tcp" 2>/dev/null || true
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
# Main
|
||||
trap cleanup SIGINT SIGTERM
|
||||
trap 'echo -e "\n${RED}Shutting down...${NC}"; kill 0; exit 0' SIGINT SIGTERM
|
||||
|
||||
kill_existing
|
||||
generate_index
|
||||
kill_port
|
||||
|
||||
echo -e "${GREEN}Starting development servers...${NC}"
|
||||
echo ""
|
||||
echo -e " Index: ${BLUE}http://localhost:$INDEX_PORT${NC}"
|
||||
echo -e " 223015b: ${BLUE}http://localhost:$COURSE_B_PORT${NC}"
|
||||
echo -e " 223015c: ${BLUE}http://localhost:$COURSE_C_PORT${NC}"
|
||||
echo ""
|
||||
echo -e "Press ${RED}Ctrl+C${NC} to stop all servers"
|
||||
if [ -n "$COURSE" ]; then
|
||||
SERVE_DIR="$SLIDES_DIR/$COURSE"
|
||||
echo -e "${GREEN}Marp dev server${NC} · ${BLUE}$COURSE${NC}"
|
||||
else
|
||||
SERVE_DIR="$SLIDES_DIR"
|
||||
echo -e "${GREEN}Marp dev server${NC} · ${BLUE}all courses${NC}"
|
||||
fi
|
||||
|
||||
echo -e " ${BLUE}http://localhost:$DEV_PORT${NC}"
|
||||
echo -e " ${BLUE}$SERVE_DIR/${NC}"
|
||||
echo ""
|
||||
|
||||
# Start servers
|
||||
python3 -m http.server $INDEX_PORT --directory "$DEV_INDEX_DIR" &
|
||||
PID_INDEX=$!
|
||||
|
||||
PORT=$COURSE_B_PORT npx @marp-team/marp-cli --server "$SLIDES_DIR/223015b/" &
|
||||
PID_B=$!
|
||||
|
||||
sleep 3 # Stagger starts to avoid WebSocket port collision
|
||||
|
||||
PORT=$COURSE_C_PORT npx @marp-team/marp-cli --server "$SLIDES_DIR/223015c/" &
|
||||
PID_C=$!
|
||||
|
||||
# Wait for any process to exit
|
||||
wait
|
||||
PORT=$DEV_PORT exec npx @marp-team/marp-cli --server "$SERVE_DIR/"
|
||||
@@ -1,19 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
# Extract klausur-relevant slides from all kapitel
|
||||
# Usage: ./extract-klausur.sh <course_id>
|
||||
# Output: slides/<course>/klausur.md
|
||||
# Output: slides/<course>/klausurfolien.md
|
||||
|
||||
set -e
|
||||
|
||||
COURSE="${1:-223015b}"
|
||||
SLIDES_DIR="slides/$COURSE"
|
||||
OUTPUT_FILE="$SLIDES_DIR/klausur.md"
|
||||
OUTPUT_FILE="$SLIDES_DIR/klausurfolien.md"
|
||||
|
||||
# Find the first kapitel file (01-*.md) to copy styles from
|
||||
FIRST_KAPITEL=$(ls "$SLIDES_DIR"/01-*.md 2>/dev/null | head -1)
|
||||
# Find the first kapitel file (00-intro.md or 01-*.md) to copy styles from
|
||||
FIRST_KAPITEL=$(ls "$SLIDES_DIR"/00-intro.md "$SLIDES_DIR"/01-*.md 2>/dev/null | head -1)
|
||||
|
||||
if [[ -z "$FIRST_KAPITEL" ]]; then
|
||||
echo "Error: No 01-*.md file found in $SLIDES_DIR"
|
||||
echo "Error: No 00-intro.md or 01-*.md file found in $SLIDES_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -57,7 +57,7 @@ awk '
|
||||
' "$FIRST_KAPITEL" >> "$OUTPUT_FILE"
|
||||
|
||||
# Process each kapitel file in order - extract klausur slides only
|
||||
for md_file in $(ls "$SLIDES_DIR"/[0-9][0-9]-*.md 2>/dev/null | grep -v klausur | sort); do
|
||||
for md_file in $(ls "$SLIDES_DIR"/[0-9][0-9]-*.md 2>/dev/null | grep -v klausurfolien | sort); do
|
||||
filename=$(basename "$md_file")
|
||||
kapitel_num=$(echo "$filename" | grep -oE '^[0-9]+' | sed 's/^0*//')
|
||||
|
||||
|
||||
@@ -42,6 +42,15 @@ TOPIC_MAP["geschichte-grundlagen-html"]="Geschichte, Grundlagen & HTML"
|
||||
TOPIC_MAP["netzwerke-protokolle-css"]="Netzwerke, Protokolle & CSS"
|
||||
TOPIC_MAP["interaktivitaet-javascript"]="Interaktivität & JavaScript"
|
||||
|
||||
# Configure which topics should appear disabled per course
|
||||
# Two modes: fully disabled (non-clickable card) and buttons-disabled (link remains clickable, buttons are disabled)
|
||||
declare -A DISABLED_FULL
|
||||
declare -A DISABLED_BUTTONS
|
||||
# For course B: chapters 3,4,5 should be fully disabled
|
||||
DISABLED_FULL["223015b"]="speichermedien-schnittstellen distribution-apis-zukunft vertiefung-offene-fragen"
|
||||
# For course C: chapter 3 should keep link clickable but buttons disabled
|
||||
DISABLED_BUTTONS["223015c"]="interaktivitaet-javascript"
|
||||
|
||||
cat > "$BUILD_DIR/index.html" << HEADER
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
@@ -61,6 +70,15 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
line-height: 1.5;
|
||||
}
|
||||
header { margin-bottom: 2rem; }
|
||||
.breadcrumb {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.breadcrumb a {
|
||||
color: #86868b;
|
||||
text-decoration: none;
|
||||
}
|
||||
.breadcrumb a:hover { text-decoration: underline; }
|
||||
h1 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 600;
|
||||
@@ -68,6 +86,12 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
margin-bottom: 0.5rem;
|
||||
color: $ACCENT_COLOR;
|
||||
}
|
||||
.course-heading {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 500;
|
||||
color: #1d1d1f;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.subtitle {
|
||||
color: #86868b;
|
||||
font-size: 0.95rem;
|
||||
@@ -77,7 +101,8 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
.kapitel {
|
||||
/* Use the .termine wrapper and add a gap between cards */
|
||||
.termine {
|
||||
margin-top: 1.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -93,6 +118,7 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
grid-template-columns: 1fr auto auto;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
padding: 0; /* inner padding handled by kapitel-link */
|
||||
}
|
||||
.kapitel-card:hover {
|
||||
transform: translateY(-2px);
|
||||
@@ -105,6 +131,8 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
color: inherit;
|
||||
grid-column: 1;
|
||||
}
|
||||
/* Disabled look: dim the entire card and prevent pointer events */
|
||||
.kapitel-card.disabled { opacity: 0.6; pointer-events: none; }
|
||||
.kapitel-label {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
@@ -135,11 +163,11 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.btn-slides {
|
||||
background: $ACCENT_COLOR;
|
||||
color: #fff;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.btn-slides:hover {
|
||||
filter: brightness(1.1);
|
||||
@@ -147,9 +175,9 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
.btn-pdf {
|
||||
background: #f5f5f7;
|
||||
color: #1d1d1f;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
.btn-pdf:hover { background: #e8e8ed; }
|
||||
.btn-disabled { opacity: 0.6; pointer-events: none; }
|
||||
/* Make entire card clickable via overlay */
|
||||
.kapitel-link::after {
|
||||
content: '';
|
||||
@@ -198,9 +226,11 @@ cat > "$BUILD_DIR/index.html" << HEADER
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>$TITLE</h1>
|
||||
<p class="breadcrumb"><a href="../">← Kursübersicht</a></p>
|
||||
<h1>HdM Vorlesungen</h1>
|
||||
<h2 class="course-heading">$TITLE</h2>
|
||||
<p class="subtitle">$SUBTITLE</p>
|
||||
<p class="meta">HdM Stuttgart · Wintersemester 2025/26 · Michael Czechowski</p>
|
||||
<p class="meta">HdM Stuttgart · Sommersemester 2026 · Michael Czechowski</p>
|
||||
</header>
|
||||
<div class="termine">
|
||||
HEADER
|
||||
@@ -216,7 +246,7 @@ for html in $(ls "$BUILD_DIR"/[0-9][0-9]-*.html 2>/dev/null | sort); do
|
||||
# Look up nice topic name or fallback
|
||||
topic="${TOPIC_MAP[$topic_raw]}"
|
||||
if [[ -z "$topic" ]]; then
|
||||
topic=$(echo "$topic_raw" | sed 's/-/ /g' | sed 's/.*/\u&/')
|
||||
topic=$(echo "$topic_raw" | sed 's/-/ /g' | sed 's/.*/\\u&/')
|
||||
fi
|
||||
|
||||
# Handle kapitel number
|
||||
@@ -228,42 +258,108 @@ for html in $(ls "$BUILD_DIR"/[0-9][0-9]-*.html 2>/dev/null | sort); do
|
||||
|
||||
pdf_filename="${filename%.html}.pdf"
|
||||
|
||||
# Check if PDF exists
|
||||
pdf_link=""
|
||||
if [[ -f "$BUILD_DIR/$pdf_filename" ]]; then
|
||||
pdf_link="<a href=\"$pdf_filename\" class=\"btn btn-pdf\">PDF</a>"
|
||||
# Determine whether this topic is configured as disabled for this course
|
||||
disabled_full=false
|
||||
disabled_buttons=false
|
||||
for t in ${DISABLED_FULL["$COURSE"]}; do
|
||||
if [[ "$topic_raw" == "$t" ]]; then
|
||||
disabled_full=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "$disabled_full" == false ]]; then
|
||||
for t in ${DISABLED_BUTTONS["$COURSE"]}; do
|
||||
if [[ "$topic_raw" == "$t" ]]; then
|
||||
disabled_buttons=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Decide card class
|
||||
card_class="kapitel-card"
|
||||
if [[ "$disabled_full" == true ]] || [[ "$disabled_buttons" == true ]]; then
|
||||
card_class="$card_class disabled"
|
||||
fi
|
||||
|
||||
# Build link/button HTML depending on disabled state
|
||||
if [[ "$disabled_full" == true ]]; then
|
||||
# non-interactive card (visually dimmed and not clickable)
|
||||
link_html="<div class=\"kapitel-link\"><div class=\"kapitel-label\">$kapitel_label</div><div class=\"kapitel-title\">$topic</div></div>"
|
||||
slides_html="<span class=\"btn btn-slides btn-disabled\">Folien</span>"
|
||||
pdf_html=""
|
||||
if [[ -f "$BUILD_DIR/$pdf_filename" ]]; then
|
||||
pdf_html="<span class=\"btn btn-pdf btn-disabled\">PDF</span>"
|
||||
fi
|
||||
elif [[ "$disabled_buttons" == true ]]; then
|
||||
# link stays clickable, but buttons are disabled; card appears dimmed
|
||||
link_html="<a href=\"$filename\" class=\"kapitel-link\"><div class=\"kapitel-label\">$kapitel_label</div><div class=\"kapitel-title\">$topic</div></a>"
|
||||
slides_html="<span class=\"btn btn-slides btn-disabled\">Folien</span>"
|
||||
pdf_html=""
|
||||
if [[ -f "$BUILD_DIR/$pdf_filename" ]]; then
|
||||
pdf_html="<span class=\"btn btn-pdf btn-disabled\">PDF</span>"
|
||||
fi
|
||||
else
|
||||
# normal interactive card
|
||||
pdf_link=""
|
||||
if [[ -f "$BUILD_DIR/$pdf_filename" ]]; then
|
||||
pdf_link="<a href=\"$pdf_filename\" class=\"btn btn-pdf\">PDF</a>"
|
||||
fi
|
||||
link_html="<a href=\"$filename\" class=\"kapitel-link\"><div class=\"kapitel-label\">$kapitel_label</div><div class=\"kapitel-title\">$topic</div></a>"
|
||||
slides_html="<a href=\"$filename\" class=\"btn btn-slides\">Folien</a>"
|
||||
pdf_html="$pdf_link"
|
||||
fi
|
||||
|
||||
cat >> "$BUILD_DIR/index.html" << LINK
|
||||
<div class="kapitel-card">
|
||||
<a href="$filename" class="kapitel-link">
|
||||
<div class="kapitel-label">$kapitel_label</div>
|
||||
<div class="kapitel-title">$topic</div>
|
||||
</a>
|
||||
<a href="$filename" class="btn btn-slides">Folien</a>
|
||||
$pdf_link
|
||||
<div class="$card_class">
|
||||
$link_html
|
||||
$slides_html
|
||||
$pdf_html
|
||||
</div>
|
||||
LINK
|
||||
|
||||
done
|
||||
|
||||
# Add klausur entry if it exists
|
||||
if [[ -f "$BUILD_DIR/klausur.html" ]]; then
|
||||
pdf_link=""
|
||||
if [[ -f "$BUILD_DIR/klausur.pdf" ]]; then
|
||||
pdf_link="<a href=\"klausur.pdf\" class=\"btn btn-pdf\">PDF</a>"
|
||||
# Add klausurfolien entry if it exists (disabled — wird noch überarbeitet)
|
||||
if [[ -f "$BUILD_DIR/klausurfolien.html" ]]; then
|
||||
pdf_disabled=""
|
||||
if [[ -f "$BUILD_DIR/klausurfolien.pdf" ]]; then
|
||||
pdf_disabled="<span class=\"btn btn-pdf btn-disabled\">PDF</span>"
|
||||
fi
|
||||
cat >> "$BUILD_DIR/index.html" << KLAUSUR
|
||||
<div class="kapitel-card" style="border-left: 3px solid $ACCENT_COLOR;">
|
||||
<a href="klausur.html" class="kapitel-link">
|
||||
<div class="kapitel-card disabled" style="border-left: 3px solid $ACCENT_COLOR;">
|
||||
<div class="kapitel-link">
|
||||
<div class="kapitel-label">Prüfung</div>
|
||||
<div class="kapitel-title">Klausurrelevante Folien</div>
|
||||
</a>
|
||||
<a href="klausur.html" class="btn btn-slides">Folien</a>
|
||||
$pdf_link
|
||||
</div>
|
||||
<span class="btn btn-slides btn-disabled">Folien</span>
|
||||
$pdf_disabled
|
||||
</div>
|
||||
KLAUSUR
|
||||
fi
|
||||
|
||||
# Add klausurfragen entry if it exists (disabled — wird noch überarbeitet)
|
||||
if [[ -f "$BUILD_DIR/klausurfragen.html" ]] || [[ -f "$BUILD_DIR/klausurfragen.pdf" ]]; then
|
||||
pdf_disabled=""
|
||||
if [[ -f "$BUILD_DIR/klausurfragen.pdf" ]]; then
|
||||
pdf_disabled="<span class=\"btn btn-pdf btn-disabled\">PDF</span>"
|
||||
fi
|
||||
slides_disabled=""
|
||||
if [[ -f "$BUILD_DIR/klausurfragen.html" ]]; then
|
||||
slides_disabled="<span class=\"btn btn-slides btn-disabled\">Folien</span>"
|
||||
fi
|
||||
cat >> "$BUILD_DIR/index.html" << KLAUSURFRAGEN
|
||||
<div class="kapitel-card disabled" style="border-left: 3px solid $ACCENT_COLOR;">
|
||||
<div class="kapitel-link">
|
||||
<div class="kapitel-label">Prüfung</div>
|
||||
<div class="kapitel-title">Klausurfragen</div>
|
||||
</div>
|
||||
$slides_disabled
|
||||
$pdf_disabled
|
||||
</div>
|
||||
KLAUSURFRAGEN
|
||||
fi
|
||||
|
||||
cat >> "$BUILD_DIR/index.html" << FOOTER
|
||||
</div>
|
||||
<div class="qr-section">
|
||||
@@ -272,7 +368,7 @@ cat >> "$BUILD_DIR/index.html" << FOOTER
|
||||
</div>
|
||||
<footer>
|
||||
<a href="mailto:mail@librete.ch">Kontakt</a> ·
|
||||
<a href="../">Alle Kurse</a>
|
||||
<a href="../">Kursübersicht</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env bash
|
||||
# Generate root index.html for HdM slides overview
|
||||
# Usage: ./generate-root-index.sh
|
||||
|
||||
BUILD_DIR="${1:-build}"
|
||||
|
||||
cat > "$BUILD_DIR/index.html" << 'HEADER'
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>HdM Vorlesungen</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, sans-serif;
|
||||
max-width: 720px;
|
||||
margin: 0 auto;
|
||||
padding: 3rem 1.5rem;
|
||||
background: #fafafa;
|
||||
color: #1d1d1f;
|
||||
line-height: 1.5;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.02em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.subtitle { color: #86868b; font-size: 1rem; }
|
||||
.courses {
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
.course-card {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
||||
transition: all 0.2s ease;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
.course-card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.12);
|
||||
}
|
||||
.course-link {
|
||||
display: block;
|
||||
padding: 1.25rem 1.5rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
grid-column: 1;
|
||||
}
|
||||
.course-link::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.course-label {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.course-b .course-label { color: #1e5f8a; }
|
||||
.course-c .course-label { color: #d63384; }
|
||||
.course-title {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 500;
|
||||
color: #1d1d1f;
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
.course-info { font-size: 0.85rem; color: #86868b; }
|
||||
.section-title {
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
color: #86868b;
|
||||
margin-top: 2.5rem;
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.references {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
footer {
|
||||
margin-top: 2.5rem;
|
||||
padding-top: 1.5rem;
|
||||
border-top: 1px solid #e5e5e7;
|
||||
color: #86868b;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
footer a { color: #1d1d1f; text-decoration: none; }
|
||||
footer a:hover { text-decoration: underline; }
|
||||
.qr-section {
|
||||
margin-top: 2.5rem;
|
||||
padding: 1.5rem;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
||||
text-align: center;
|
||||
}
|
||||
.qr-code { width: 100%; height: auto; }
|
||||
.qr-url { margin-top: 0.75rem; font-size: 0.85rem; color: #86868b; }
|
||||
@media (max-width: 600px) {
|
||||
.course-card { grid-template-columns: 1fr; }
|
||||
.course-link { padding-bottom: 0.75rem; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>HdM Vorlesungen</h1>
|
||||
<p class="subtitle">Sommersemester 2026 · Michael Czechowski</p>
|
||||
<div class="courses">
|
||||
<div class="course-card course-b">
|
||||
<a href="223015b/" class="course-link">
|
||||
<span class="course-label">223015b</span>
|
||||
<div class="course-title">Dateiformate, Schnittstellen, Speichermedien & Distributionswege</div>
|
||||
<span class="course-info">6 Kapitel · Modul "Technik 1"</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="course-card course-c">
|
||||
<a href="223015c/" class="course-link">
|
||||
<span class="course-label">223015c</span>
|
||||
<div class="course-title">Grundlagen IT- und Internettechnik</div>
|
||||
<span class="course-info">3 Kapitel · Modul "Technik 1"</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="section-title">Referenzen</h2>
|
||||
<div class="references">
|
||||
<div class="course-card">
|
||||
<a href="https://codecrispi.es/" class="course-link">
|
||||
<span class="course-label">Plattform</span>
|
||||
<div class="course-title">Code Crispies</div>
|
||||
<span class="course-info">Selbstlernplattform</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="qr-section">
|
||||
<img src="qr-root.svg" alt="QR Code" class="qr-code">
|
||||
<p class="qr-url">https://librete.ch/hdm/</p>
|
||||
</div>
|
||||
<footer>
|
||||
<a href="mailto:mail@librete.ch">Kontakt</a>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
HEADER
|
||||
|
||||
echo "Generated $BUILD_DIR/index.html"
|
||||
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Dateiformate, Schnittstellen, Speichermedien & Distributionswege (223015b)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – WS 2025/26"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Dateiformate, Schnittstellen, Speichermedien & Distributionswege
|
||||
---
|
||||
|
||||
@@ -82,173 +82,109 @@ section.aufgabe footer {
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Wintersemester 2025/26**
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015b/](https://librete.ch/hdm/223015b/)
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
<!-- _class: lead -->
|
||||
|
||||
# Willkommen!
|
||||
# Herzlich willkommen!
|
||||
## Einführung
|
||||
|
||||
---
|
||||
|
||||
# Über mich
|
||||
|
||||
**Michael Czechowski**
|
||||
**Michael Werner Czechowski**
|
||||
|
||||
- Irgendwas mit IT, Cloud und AI
|
||||
- Systems and Platform Engineer
|
||||
- Schwerpunkte:
|
||||
- Web-Technologien, Barriere-Armut, Systemarchitektur, Open Source
|
||||
- Hintergrund:
|
||||
- Philosophie (Uni Stuttgart) -> NO degree
|
||||
- Wirtschafts-Informatik (Leibniz-FH) -> B.Sc.
|
||||
- Philosophie (Uni Stuttgart)
|
||||
- Wirtschaftsinformatik (Leibniz-FH Hannover)
|
||||
- Kontakt: lb-czechowski@hdm-stuttgart.de
|
||||
|
||||
---
|
||||
|
||||
# Warum dieses Modul?
|
||||
|
||||
**Digitale Medien sind überall.**
|
||||
|
||||
* Warum enthalten Fotos oft Informationen über den Aufnahmeort?
|
||||
* Warum lassen sich gelöschte Dateien wiederherstellen?
|
||||
* Warum benötigt eine Minute 4K-Video unkomprimiert 45 GB Speicher?
|
||||
* Warum zeigt eine "1 TB"-Festplatte nur 931 GB an?
|
||||
* Warum ist USB-C nicht gleich USB-C?
|
||||
* Ziel: **→ Mitreden können!**
|
||||
|
||||
<!--
|
||||
Kurze Vorstellung
|
||||
Praxisbezug betonen
|
||||
Fragen jederzeit willkommen
|
||||
1. EXIF (Exchangeable Image File Format)-Metadaten speichern GPS-Koordinaten, Kameramodell und Zeitstempel automatisch. Die meisten wissen nicht, dass diese Daten beim Versenden mitgeschickt werden. → Kapitel 4: Metadaten
|
||||
|
||||
2. Beim Löschen wird nur der Verzeichniseintrag im Dateisystem entfernt, nicht die Daten selbst. Die Bits bleiben auf dem Datenträger, bis sie überschrieben werden. → Kapitel 3: Dateisysteme
|
||||
|
||||
3. 3840 × 2160 Pixel × 3 Byte (RGB) × 30 Bilder/Sek × 60 Sek = ~45 GB. Codecs wie H.264/H.265 komprimieren um Faktor 100+. → Kapitel 1+2: Kompression
|
||||
|
||||
4. Hersteller rechnen dezimal (1 TB = 10¹² Bytes), Betriebssysteme binär (1 TiB = 2⁴⁰ Bytes). Die Differenz beträgt bei Terabyte bereits ~10%. → Kapitel 1: Dateneinheiten
|
||||
|
||||
5. USB-C ist nur die Steckerform. Dahinter können USB 2.0 (480 Mbit/s), USB 3.2 (20 Gbit/s) oder Thunderbolt 4 (40 Gbit/s) laufen — gleiches Kabel, völlig unterschiedliche Leistung. → Kapitel 3: Schnittstellen
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
# AMA (Ask my anything)
|
||||
|
||||
*Nur ein Vorschlag ...*
|
||||
|
||||
* Hast du alle Bände von AoT daheim?
|
||||
* Hast du eine Studierenden-Kneipe mal geleitet?
|
||||
* Hast du wirklich 17 Semester Philosophie ohne Abschluss studiert?
|
||||
|
||||
---
|
||||
|
||||
# Kurze Umfrage
|
||||
|
||||
**Bitte Hand heben:**
|
||||
|
||||
1) Wer hat schon mal ein Video komprimiert/konvertiert?
|
||||
2) Wer kennte die 3-2-1 Regel?
|
||||
3) Wer weiß, was der Unterschied zwischen JPEG und PNG ist?
|
||||
4) Wer hat schon mal mit APIs gearbeitet?
|
||||
5) Wer weiß, was UTF-8 bedeutet?
|
||||
6) Wer hat schon mal mit einem CLI gearbeitet?
|
||||
6) **Wer hat schon mal etwas mit HTML oder CSS gemacht?** (Hex-Farben wie `#FF0000`?)
|
||||
* Wer kennt den Unterschied zwischen analog und digital?
|
||||
* Wer hat schon mal eine Datei von einem Format in ein anderes konvertiert?
|
||||
* Wer hat schon mal Metadaten aus einem Foto entfernt?
|
||||
* Wer hat schon mal ein Backup verloren?
|
||||
* Wer hat schon mal ein Backup wiederhergestellt?
|
||||
|
||||
<!--
|
||||
Niveau der Gruppe einschätzen
|
||||
Keine falschen Antworten
|
||||
Zeigt, wo wir starten
|
||||
HTML/CSS-Frage: Viele kennen Hex-Codes aus Webdesign
|
||||
API = Application Programming Interface
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
# Warum dieses Modul?
|
||||
|
||||
**Digitale Medien sind überall** – aber was steckt dahinter?
|
||||
|
||||
* Warum ist ein JPEG kleiner als ein PNG?
|
||||
* Warum klingt MP3 anders als FLAC?
|
||||
* Warum zeigt meine 1 TB Festplatte nur 931 GB?
|
||||
* Warum ist USB-C so verwirrend?
|
||||
* Wie funktioniert eigentlich Streaming?
|
||||
* **→ Die Technik dahinter verstehen!**
|
||||
|
||||
<!--
|
||||
Praxisnahe Fragen aus dem Alltag
|
||||
Nicht nur "was", sondern "warum"
|
||||
Verständnis für technische Entscheidungen
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
# Das Ziel
|
||||
|
||||
**Technische Grundlagen verstehen**, um fundierte Entscheidungen treffen zu können.
|
||||
|
||||
Als Digital- und Medienwirtschaftler:innen werdet ihr täglich mit technischen Fragen konfrontiert:
|
||||
* Welches Format für welchen Zweck?
|
||||
* Welche Schnittstelle für welches Gerät?
|
||||
* Wie funktioniert die Distribution digitaler Inhalte?
|
||||
* **→ Mitreden können – nicht (zwingend) programmieren!**
|
||||
|
||||
<!--
|
||||
Nicht: Ihr sollt Programmierer werden
|
||||
Sondern: Ihr sollt technische Entscheidungen verstehen
|
||||
Praxisbezug: Medienproduktion, Marketing, Projektmanagement
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
# Was ihr lernt
|
||||
|
||||
**In dieser Veranstaltung erwerbt ihr folgende Kompetenzen:**
|
||||
|
||||
* Fundiertes Grundwissen über Daten und Informationen
|
||||
* Dateiformate analysieren und verstehen
|
||||
* Grundlagen von Kompression (Audio, Bild, Video)
|
||||
* Speichermedien unterscheiden
|
||||
* Programmier-Schnittstellen kennenlernen
|
||||
* APIs und Distributionswege verstehen
|
||||
|
||||
<!--
|
||||
Fokus auf Verständnis, nicht auf Programmierung
|
||||
Hands-On jede Woche: Selbst ausprobieren
|
||||
Ziel: Einblick in die Denkweise von Software-Entwicklern
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
# Kursübersicht
|
||||
|
||||
**5 Termine:**
|
||||
**Kapitel:**
|
||||
|
||||
| # | Datum | Thema |
|
||||
|---|-------|-------|
|
||||
| 1 | 19.12.2025 | Bits, Bytes, Zeichenkodierung & Audio |
|
||||
| 2 | 09.01.2026 | Bild- & Video-Kompression |
|
||||
| 3 | 23.01.2026 | Speichermedien & Schnittstellen |
|
||||
| 4 | 30.01.2026 | Distribution, APIs & Zukunft |
|
||||
| 5 | TBA | Vertiefung & offene Fragen |
|
||||
* 1. **Grundlagen**, Text & Audio (Bits, Bytes, Zeichenkodierung, MP3)
|
||||
* 2. Bild- & Video-**Kompression** (JPEG, PNG, H.264/H.265)
|
||||
* 3. **Speichermedien** & **Schnittstellen** (HDD, SSD, USB, Thunderbolt)
|
||||
* 4. **Distribution** und Verteilung (Streaming, REST, Cloud)
|
||||
* Vertiefung & offene Fragen
|
||||
|
||||
**Format:** Theorie + Hands-On (30-40 Min pro Termin)
|
||||
|
||||
<!--
|
||||
Nicht nur theoretische Inhalte
|
||||
Praktische Übungen jede Woche
|
||||
Medienwissenschaftler:innen, nicht Informatiker:innen
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
# Prüfungsleistung 18.02.
|
||||
<!-- _class: klausur -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
<!-- _backgroundColor: #e3f2fd -->
|
||||
|
||||
# Prüfungsleistung
|
||||
|
||||
**Nach aktuellem Kenntnisstand:**
|
||||
|
||||
* 90 min (40% Grundlagen, 40% Dateiformate, 20% AV)
|
||||
* Schriftliche Klausur
|
||||
* 90 min insg. (Technik 1)
|
||||
* Schriftliche Klausur (digital)
|
||||
* Teils offene Fragen
|
||||
* Vermutlich digital
|
||||
* Kein Coding!
|
||||
* **Prüfungsrelevant:** Alles in den Folien/im Skript
|
||||
|
||||
<!--
|
||||
Details können sich noch ändern
|
||||
Keine Programmieraufgaben
|
||||
Verständnisfragen, keine Auswendiglernerei
|
||||
-->
|
||||
|
||||
* Kein Coding/Programmieren
|
||||
* **Prüfungsrelevante Folien:**
|
||||
- Gestreift oder Vollton (PDF) markiert
|
||||
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Dateiformate, Schnittstellen, Speichermedien & Distributionswege (223015b)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Dateiformate, Schnittstellen, Speichermedien & Distributionswege
|
||||
---
|
||||
|
||||
@@ -68,6 +68,38 @@ section.aufgabe {
|
||||
section.aufgabe footer {
|
||||
display: none;
|
||||
}
|
||||
section.erklaerung {
|
||||
font-size: 1.1rem;
|
||||
background: repeating-linear-gradient(
|
||||
135deg,
|
||||
#e3f2fd,
|
||||
#e3f2fd 40px,
|
||||
#fff 40px,
|
||||
#fff 80px
|
||||
) !important;
|
||||
}
|
||||
@media print {
|
||||
section.erklaerung {
|
||||
background: #e3f2fd !important;
|
||||
}
|
||||
}
|
||||
section.erklaerung h1 {
|
||||
font-size: 1.5rem;
|
||||
color: #1e5f8a;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
section.erklaerung ul,
|
||||
section.erklaerung ol {
|
||||
font-size: 1.0rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
section.erklaerung p {
|
||||
font-size: 1.0rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
section.erklaerung table {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- _class: invert -->
|
||||
@@ -220,6 +252,26 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# Rastergrafik – Vertiefung
|
||||
|
||||
Ein Pixel ist die kleinste adressierbare Einheit. Bei 24-Bit-Farbtiefe speichert jeder Pixel drei 8-Bit-Werte (0–255) für Rot, Grün und Blau. Diese additive Farbmischung erzeugt 256³ = 16,7 Millionen mögliche Farbtöne.
|
||||
|
||||
**Speicherberechnung:** `Breite × Höhe × Bytes pro Pixel`
|
||||
|
||||
| Auflösung | Farbtiefe | Berechnung | Größe |
|
||||
|-----------|-----------|------------|-------|
|
||||
| 1920×1080 | 24 Bit (3 B) | 2.073.600 × 3 | 6,2 MB |
|
||||
| 4K (3840×2160) | 24 Bit | 8.294.400 × 3 | 24,9 MB |
|
||||
| 4K | 32 Bit (4 B) | 8.294.400 × 4 | 33,2 MB |
|
||||
|
||||
Der Alpha-Kanal (32 Bit) speichert Transparenz als Wert von 0 (unsichtbar) bis 255 (vollständig sichtbar). PNG nutzt dies für weiche Kanten; JPEG unterstützt keinen Alpha-Kanal.
|
||||
|
||||
---
|
||||
|
||||
# Das Problem der Skalierung
|
||||
|
||||
**Vergrößern:**
|
||||
@@ -274,6 +326,30 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# Vektorgrafik – Vertiefung
|
||||
|
||||
Vektorgrafiken speichern keine Pixel, sondern mathematische Beschreibungen: Koordinaten, Kurvenparameter (Bézier-Kontrollpunkte), Füllfarben, Strichstärken. Der Renderer berechnet die Pixel erst bei der Ausgabe – daher beliebig skalierbar.
|
||||
|
||||
**Bézier-Kurven** (Pierre Bézier, 1962, für Renault-Karosserien entwickelt):
|
||||
- Definiert durch Ankerpunkte und Kontrollpunkte
|
||||
- Kubische Bézier: 2 Anker + 2 Kontrollpunkte
|
||||
- Mathematisch exakt reproduzierbar
|
||||
|
||||
| Aspekt | Raster | Vektor |
|
||||
|--------|--------|--------|
|
||||
| Skalierung 10× | Pixel sichtbar | Perfekt scharf |
|
||||
| Foto-Realismus | Gut geeignet | Unpraktikabel |
|
||||
| Dateigröße Logo | Wächst mit Auflösung | Konstant (~5 KB) |
|
||||
| Editierbarkeit | Destruktiv | Nicht-destruktiv |
|
||||
|
||||
**Rasterisierung:** GPU wandelt Vektordaten in Pixel um. Geschieht bei jeder Darstellung neu – deshalb ist ein 4K-Monitor schärfer als ein 1080p-Monitor bei gleichem SVG.
|
||||
|
||||
---
|
||||
|
||||
# Raster- und Vektorgrafiken
|
||||
|
||||
| | Raster | Vektor |
|
||||
@@ -338,6 +414,28 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# Psychovisuelle Wahrnehmung – Vertiefung
|
||||
|
||||
Die Netzhaut enthält ~120 Mio. Stäbchen (Helligkeitswahrnehmung) aber nur ~6 Mio. Zapfen (Farbwahrnehmung). Dieses 20:1-Verhältnis erklärt, warum JPEG Farbinformationen stärker reduzieren kann als Helligkeitsinformationen.
|
||||
|
||||
**Räumliche Frequenz** beschreibt, wie schnell sich die Helligkeit über eine Bildfläche ändert:
|
||||
- **Niedrig:** Himmel, Wand – große einheitliche Flächen
|
||||
- **Hoch:** Haare, Texturen, Schrift – schnelle Wechsel
|
||||
|
||||
Das Auge ist ein Tiefpassfilter: Hohe Frequenzen (feine Details) werden schwächer wahrgenommen. JPEG verwirft daher zuerst die hohen Frequenzen – der Qualitätsverlust bleibt meist unsichtbar.
|
||||
|
||||
| Biologisches Limit | Ausnutzung in JPEG |
|
||||
|-------------------|-------------------|
|
||||
| Farbauflösung ~20× geringer | Chroma Subsampling (4:2:0) |
|
||||
| Hohe Frequenzen unscharf | DCT + Quantisierung |
|
||||
| Kontrast-Maskierung | Artefakte in Texturen versteckt |
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
@@ -442,6 +540,34 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# Farbraumkonversion – Vertiefung
|
||||
|
||||
RGB→YCbCr nutzt die Biologie des menschlichen Auges: 120 Mio. Stäbchen (Helligkeit) vs. nur 6 Mio. Zapfen (Farbe) – ein 20:1-Verhältnis. Die Transformation erfolgt über eine lineare Matrix:
|
||||
|
||||
```
|
||||
Y = 0.299·R + 0.587·G + 0.114·B
|
||||
Cb = −0.169·R − 0.331·G + 0.500·B + 128
|
||||
Cr = 0.500·R − 0.419·G − 0.081·B + 128
|
||||
```
|
||||
|
||||
Die Gewichtung (G dominiert mit 59%) entspricht der spektralen Empfindlichkeit des Auges bei Tageslicht. Y enthält alle Schärfeinformation; Cb/Cr können reduziert werden.
|
||||
|
||||
**Chroma Subsampling – Notation J:a:b** (bezogen auf 4×2 Pixel):
|
||||
|
||||
| Schema | Farbdaten | Einsatz |
|
||||
|--------|-----------|---------|
|
||||
| 4:4:4 | 100% | Postproduktion, Grafik |
|
||||
| 4:2:2 | 50% | Broadcast, Pro-Video |
|
||||
| 4:2:0 | 25% | JPEG, H.264, Streaming |
|
||||
|
||||
Bei 4:2:0 teilen sich 4 Pixel einen Farbwert, behalten aber individuelle Helligkeit → 50% Dateneinsparung bei kaum sichtbarem Unterschied.
|
||||
|
||||
---
|
||||
|
||||
# JPEG Schritt 2: Chroma Subsampling
|
||||
|
||||
**Notation `J:a:b`** (bezogen auf 4×2 Pixel-Block):
|
||||
@@ -623,12 +749,36 @@ KLAUSURRELEVANT:
|
||||
- Präfix-frei: Kein Code ist Anfang eines anderen
|
||||
- Häufigstes Zeichen = kürzester Code
|
||||
- Auch in ZIP, PNG, MP3 verwendet
|
||||
-->
|
||||
|
||||
---
|
||||
|
||||
-->
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# Huffman-Coding – Vertiefung
|
||||
|
||||
David Huffman entwickelte 1952 als Student am MIT einen optimalen Algorithmus für präfixfreie Codes – ursprünglich als Hausaufgabe, die zur Veröffentlichung führte.
|
||||
|
||||
**Algorithmus (Bottom-Up-Baumkonstruktion):**
|
||||
1. Alle Symbole nach Häufigkeit sortieren
|
||||
2. Die zwei seltensten Symbole zu einem Knoten kombinieren
|
||||
3. Wiederholen bis nur noch die Wurzel übrig ist
|
||||
4. Codes ablesen: links = 0, rechts = 1
|
||||
|
||||
**Präfixfreiheit:** Kein Code ist Anfang eines anderen → sofort dekodierbar ohne Trennzeichen.
|
||||
|
||||
| Eigenschaft | Huffman | Arithmetisch |
|
||||
|-------------|---------|--------------|
|
||||
| Einheit | Ganze Bits | Fraktionale Bits |
|
||||
| Optimalität | Optimal für ganze Bits | Näher an Entropie |
|
||||
| Geschwindigkeit | Schneller | Langsamer |
|
||||
| JPEG-Einsatz | Standard (Baseline) | Optional (selten) |
|
||||
|
||||
JPEG verwendet zwei Huffman-Tabellen: eine für DC-Koeffizienten (Durchschnittswerte), eine für AC-Koeffizienten (Frequenzen). Die Tabellen sind im JPEG-Header gespeichert.
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: klausur -->
|
||||
<!-- _header: '' -->
|
||||
@@ -772,6 +922,28 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# WebP & AVIF – Vertiefung
|
||||
|
||||
**WebP** entstand 2010 aus Googles VP8-Videocodec (On2 Technologies, für $133M gekauft). Statt I-Frames für Video werden sie als Einzelbilder verwendet. WebP nutzt Intra-Frame-Prediction, die benachbarte Blöcke zur Vorhersage verwendet – effizienter als JPEGs blockweise DCT.
|
||||
|
||||
**AVIF** basiert auf dem AV1-Videocodec, entwickelt 2015–2018 von der Alliance for Open Media (Google, Apple, Netflix, Amazon, Microsoft, Mozilla). Nach dem Patent-Chaos von H.265/HEVC vereinten sich die Konkurrenten für einen lizenzfreien Standard.
|
||||
|
||||
| Aspekt | WebP | AVIF |
|
||||
|--------|------|------|
|
||||
| Basis-Codec | VP8/VP9 | AV1 |
|
||||
| Kompression vs. JPEG | 25–35% besser | 50% besser |
|
||||
| HDR/Wide Gamut | Nein | Ja (10/12 Bit) |
|
||||
| Encoding-Geschwindigkeit | Schnell | Sehr langsam |
|
||||
| Browser-Support 2025 | 97%+ | 93%+ |
|
||||
|
||||
**Warum JPEG dominiert:** Kameras, Bildbearbeitungssoftware und Content-Management-Systeme sind auf JPEG optimiert. Der Wechsel erfordert Infrastruktur-Updates über die gesamte Pipeline.
|
||||
|
||||
---
|
||||
|
||||
# Formatwahl in der Praxis
|
||||
|
||||
| Anwendung | Format |
|
||||
@@ -890,6 +1062,33 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# Container vs. Codec – Vertiefung
|
||||
|
||||
**Container** (Multiplexer-Format) organisiert mehrere Datenströme mit Timing-Informationen. Er enthält keine Kompressionslogik, sondern synchronisiert Video, Audio, Untertitel und Metadaten.
|
||||
|
||||
**Codec** (Coder-Decoder) definiert den Kompressionsalgorithmus. Derselbe Container kann verschiedene Codecs enthalten – die Dateiendung verrät den Codec nicht.
|
||||
|
||||
| Container | Entwickler | Typische Codecs | Besonderheit |
|
||||
|-----------|------------|-----------------|--------------|
|
||||
| MP4 | ISO/MPEG | H.264, H.265, AAC | Web-Standard, DRM-fähig |
|
||||
| MKV | Matroska | Alle | Beliebig viele Streams, Kapitel |
|
||||
| WebM | Google | VP9, AV1, Opus | HTML5-optimiert, lizenzfrei |
|
||||
| MOV | Apple | ProRes, H.264 | Professionelle Produktion |
|
||||
|
||||
**Metadaten im Container:**
|
||||
- Timecodes für Frame-genaue Synchronisation
|
||||
- Kapitelmarken, Thumbnails
|
||||
- Sprach-Tags für Audio/Untertitel
|
||||
- HDR-Metadaten (MaxCLL, MaxFALL)
|
||||
|
||||
**Praktisches Problem:** Eine `.mp4`-Datei mit AV1-Codec spielt auf älteren Geräten nicht ab, obwohl sie MP4 „unterstützen" – der Hardware-Decoder fehlt für AV1.
|
||||
|
||||
---
|
||||
|
||||
# Gängige Container
|
||||
|
||||
| Container | Verwendung |
|
||||
@@ -1115,6 +1314,32 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# H.264/AVC – Vertiefung
|
||||
|
||||
H.264 (2003) ermöglichte erst YouTube (2005), Netflix-Streaming (2007) und Blu-ray. Vor H.264 war MPEG-2 Standard – H.264 erreichte bei gleicher Qualität die halbe Bitrate.
|
||||
|
||||
**Technische Innovationen:**
|
||||
- **Variable Blockgrößen:** 16×16 bis 4×4 Macroblocks (MPEG-2: nur 16×16)
|
||||
- **Intra-Prediction:** Blöcke werden aus Nachbarn vorhergesagt
|
||||
- **In-Loop Deblocking:** Filter reduziert Blockartefakte vor der Referenzierung
|
||||
- **CABAC:** Arithmetic Coding ersetzt Huffman (10–15% effizienter)
|
||||
|
||||
| Profile | Anwendung | Max. Auflösung |
|
||||
|---------|-----------|----------------|
|
||||
| Baseline | Videotelefonie, ältere Geräte | 480p |
|
||||
| Main | Broadcast, Streaming | 1080p |
|
||||
| High | Blu-ray, professionell | 4K |
|
||||
|
||||
**Hardware-Ubiquität:** Seit 2010 hat jedes Smartphone, jede GPU, jeder Smart-TV einen H.264-Hardware-Decoder. Encoding in Echtzeit braucht keine CPU – das ermöglichte erst mobiles Video-Streaming und Videotelefonie.
|
||||
|
||||
**Patent-Pool (MPEG-LA):** ~2.000 Patente von 30+ Unternehmen. Endnutzer-Streaming ist lizenzfrei; Hardware-Hersteller zahlen ~$0,20/Gerät.
|
||||
|
||||
---
|
||||
|
||||
# Das Patent-Problem
|
||||
|
||||
**H.264 ist nicht frei**
|
||||
@@ -1221,6 +1446,29 @@ KLAUSURRELEVANT:
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# AV1 – Vertiefung
|
||||
|
||||
Die **Alliance for Open Media** (2015) vereinte Konkurrenten nach dem Patent-Chaos von H.265/HEVC. Drei separate Patent-Pools (MPEG-LA, HEVC Advance, Velos Media) machten H.265-Lizenzierung unberechenbar – die Industrie wollte einen garantiert lizenzfreien Standard.
|
||||
|
||||
**Gründungsmitglieder:** Google, Mozilla, Cisco, Netflix, Amazon, Microsoft. Apple trat 2018 bei – historisch, da Apple sonst eigene Standards bevorzugt.
|
||||
|
||||
| Technische Innovation | Beschreibung |
|
||||
|----------------------|--------------|
|
||||
| Superblocks | Bis 128×128 Pixel (H.264: max 16×16) |
|
||||
| Prediction Modes | 56 Intra-Modi (H.264: 9) |
|
||||
| Transform | 10 verschiedene Transformtypen |
|
||||
| Film Grain Synthesis | Filmkorn wird als Parameter übertragen |
|
||||
|
||||
**Encoding-Performance:** Software-Encoding ist 50–200× langsamer als H.264. Erst Hardware-Encoder (Intel ab Gen 12, NVIDIA RTX 40, Apple M3) machen Echtzeit-Encoding praktikabel.
|
||||
|
||||
**Adoption 2025:** YouTube und Netflix nutzen AV1 für 4K/8K-Streams. 2024 gewann AV1 einen Emmy für technische Innovation – offene Standards können Industriestandard werden.
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: 'https://blog.mozilla.org/en/mozilla/av1-video-codec-wins-emmy/' -->
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Dateiformate, Schnittstellen, Speichermedien & Distributionswege (223015b)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – WS 2025/26"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Dateiformate, Schnittstellen, Speichermedien & Distributionswege
|
||||
---
|
||||
|
||||
@@ -68,6 +68,38 @@ section.aufgabe {
|
||||
section.aufgabe footer {
|
||||
display: none;
|
||||
}
|
||||
section.erklaerung {
|
||||
font-size: 1.1rem;
|
||||
background: repeating-linear-gradient(
|
||||
135deg,
|
||||
#e3f2fd,
|
||||
#e3f2fd 40px,
|
||||
#fff 40px,
|
||||
#fff 80px
|
||||
) !important;
|
||||
}
|
||||
@media print {
|
||||
section.erklaerung {
|
||||
background: #e3f2fd !important;
|
||||
}
|
||||
}
|
||||
section.erklaerung h1 {
|
||||
font-size: 1.5rem;
|
||||
color: #1e5f8a;
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
section.erklaerung ul,
|
||||
section.erklaerung ol {
|
||||
font-size: 1.0rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
section.erklaerung p {
|
||||
font-size: 1.0rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
section.erklaerung table {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- _class: invert -->
|
||||
@@ -82,7 +114,7 @@ section.aufgabe footer {
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Wintersemester 2025/26**
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015b/](https://librete.ch/hdm/223015b/)
|
||||
|
||||
@@ -235,6 +267,29 @@ Kleine SSD für System + große HDD für Archiv.
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# HDD vs. SSD – Vertiefung
|
||||
|
||||
**HDD (Hard Disk Drive):** Magnetplatten rotieren mit 5.400–7.200 RPM; ein Schreib-/Lesekopf schwebt nanometerweit über der Oberfläche. Die Zugriffszeit setzt sich zusammen aus Seek Time (Kopf bewegen) + Rotational Latency (warten auf Sektor).
|
||||
|
||||
**SSD (Solid State Drive):** NAND-Flash-Zellen speichern Bits als elektrische Ladung. Kein mechanischer Zugriff → konstant schnelle Latenz. Aber: Zellen haben begrenzte Schreibzyklen (P/E Cycles).
|
||||
|
||||
| Aspekt | HDD | SATA SSD | NVMe SSD |
|
||||
|--------|-----|----------|----------|
|
||||
| Latenz | 5–10 ms | 0,1 ms | 0,02 ms |
|
||||
| Seq. Lesen | 150 MB/s | 550 MB/s | 7.000 MB/s |
|
||||
| IOPS (4K random) | 100 | 90.000 | 1.000.000 |
|
||||
| TBW (1 TB Modell) | ∞ | 600 TBW | 600 TBW |
|
||||
|
||||
**Wear Leveling:** SSD-Controller verteilen Schreibvorgänge gleichmäßig, um einzelne Zellen nicht vorzeitig zu erschöpfen. TRIM informiert den Controller über gelöschte Blöcke.
|
||||
|
||||
**Praxis:** System-SSD für OS/Anwendungen (Geschwindigkeit), HDD für Medienarchiv (Kapazität/Preis). RAID schützt vor Einzelausfällen bei beiden.
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: lead -->
|
||||
|
||||
# Dateisysteme
|
||||
@@ -484,6 +539,30 @@ Warum 1 Offsite?
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: erklaerung -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||
# 3-2-1-Backup-Regel – Vertiefung
|
||||
|
||||
Peter Krogh formulierte die Regel 2005 in „The DAM Book" (Digital Asset Management). Sie schützt gegen unterschiedliche Verlustszenarien:
|
||||
|
||||
| Bedrohung | Schutz durch | Beispiel |
|
||||
|-----------|--------------|----------|
|
||||
| Hardware-Defekt | 3 Kopien | SSD stirbt → HDD-Backup vorhanden |
|
||||
| Firmware-Bug/Ransomware | 2 Medientypen | Malware infiziert nur ein System |
|
||||
| Feuer/Diebstahl/Flut | 1 Offsite | Haus brennt → Cloud-Backup sicher |
|
||||
|
||||
**Moderne Erweiterung 3-2-1-1-0:**
|
||||
- **+1** Air-Gapped (offline, nicht verbunden)
|
||||
- **+0** Verifizierte Backups (regelmäßig Restore testen)
|
||||
|
||||
**Ransomware-Problem:** Vernetzte Backups werden oft mitverschlüsselt. Air-Gapped-Medien (externe HDD im Safe, LTO-Band) bleiben sicher, weil sie physisch getrennt sind.
|
||||
|
||||
**Realitäts-Check:** Die meisten Datenverluste entstehen durch menschliche Fehler (versehentliches Löschen), nicht Hardware-Ausfälle. Versionierte Backups (Time Machine, Borg) schützen auch davor – die gelöschte Datei existiert noch in älteren Snapshots.
|
||||
|
||||
---
|
||||
|
||||
# Backup-Arten
|
||||
|
||||
**Vollständig (Full):**
|
||||
|
||||
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Dateiformate, Schnittstellen, Speichermedien & Distributionswege (223015b)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – WS 2025/26"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Dateiformate, Schnittstellen, Speichermedien & Distributionswege
|
||||
---
|
||||
|
||||
@@ -83,7 +83,7 @@ section.aufgabe footer {
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Wintersemester 2025/26**
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015b/](https://librete.ch/hdm/223015b/)
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Dateiformate, Schnittstellen, Speichermedien & Distributionswege (223015b)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – WS 2025/26"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Dateiformate, Schnittstellen, Speichermedien & Distributionswege
|
||||
---
|
||||
|
||||
@@ -83,7 +83,7 @@ section.aufgabe footer {
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Wintersemester 2025/26**
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015b/](https://librete.ch/hdm/223015b/)
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 318 KiB |
@@ -0,0 +1,258 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2560 1440" preserveAspectRatio="none" shape-rendering="crispEdges">
|
||||
<rect x="0" y="0" width="10" height="1440" fill="rgb(255,255,255)"/>
|
||||
<rect x="10" y="0" width="10" height="1440" fill="rgb(254,254,254)"/>
|
||||
<rect x="20" y="0" width="10" height="1440" fill="rgb(253,253,253)"/>
|
||||
<rect x="30" y="0" width="10" height="1440" fill="rgb(252,252,252)"/>
|
||||
<rect x="40" y="0" width="10" height="1440" fill="rgb(251,251,251)"/>
|
||||
<rect x="50" y="0" width="10" height="1440" fill="rgb(250,250,250)"/>
|
||||
<rect x="60" y="0" width="10" height="1440" fill="rgb(249,249,249)"/>
|
||||
<rect x="70" y="0" width="10" height="1440" fill="rgb(248,248,248)"/>
|
||||
<rect x="80" y="0" width="10" height="1440" fill="rgb(247,247,247)"/>
|
||||
<rect x="90" y="0" width="10" height="1440" fill="rgb(246,246,246)"/>
|
||||
<rect x="100" y="0" width="10" height="1440" fill="rgb(245,245,245)"/>
|
||||
<rect x="110" y="0" width="10" height="1440" fill="rgb(244,244,244)"/>
|
||||
<rect x="120" y="0" width="10" height="1440" fill="rgb(243,243,243)"/>
|
||||
<rect x="130" y="0" width="10" height="1440" fill="rgb(242,242,242)"/>
|
||||
<rect x="140" y="0" width="10" height="1440" fill="rgb(241,241,241)"/>
|
||||
<rect x="150" y="0" width="10" height="1440" fill="rgb(240,240,240)"/>
|
||||
<rect x="160" y="0" width="10" height="1440" fill="rgb(239,239,239)"/>
|
||||
<rect x="170" y="0" width="10" height="1440" fill="rgb(238,238,238)"/>
|
||||
<rect x="180" y="0" width="10" height="1440" fill="rgb(237,237,237)"/>
|
||||
<rect x="190" y="0" width="10" height="1440" fill="rgb(236,236,236)"/>
|
||||
<rect x="200" y="0" width="10" height="1440" fill="rgb(235,235,235)"/>
|
||||
<rect x="210" y="0" width="10" height="1440" fill="rgb(234,234,234)"/>
|
||||
<rect x="220" y="0" width="10" height="1440" fill="rgb(233,233,233)"/>
|
||||
<rect x="230" y="0" width="10" height="1440" fill="rgb(232,232,232)"/>
|
||||
<rect x="240" y="0" width="10" height="1440" fill="rgb(231,231,231)"/>
|
||||
<rect x="250" y="0" width="10" height="1440" fill="rgb(230,230,230)"/>
|
||||
<rect x="260" y="0" width="10" height="1440" fill="rgb(229,229,229)"/>
|
||||
<rect x="270" y="0" width="10" height="1440" fill="rgb(228,228,228)"/>
|
||||
<rect x="280" y="0" width="10" height="1440" fill="rgb(227,227,227)"/>
|
||||
<rect x="290" y="0" width="10" height="1440" fill="rgb(226,226,226)"/>
|
||||
<rect x="300" y="0" width="10" height="1440" fill="rgb(225,225,225)"/>
|
||||
<rect x="310" y="0" width="10" height="1440" fill="rgb(224,224,224)"/>
|
||||
<rect x="320" y="0" width="10" height="1440" fill="rgb(223,223,223)"/>
|
||||
<rect x="330" y="0" width="10" height="1440" fill="rgb(222,222,222)"/>
|
||||
<rect x="340" y="0" width="10" height="1440" fill="rgb(221,221,221)"/>
|
||||
<rect x="350" y="0" width="10" height="1440" fill="rgb(220,220,220)"/>
|
||||
<rect x="360" y="0" width="10" height="1440" fill="rgb(219,219,219)"/>
|
||||
<rect x="370" y="0" width="10" height="1440" fill="rgb(218,218,218)"/>
|
||||
<rect x="380" y="0" width="10" height="1440" fill="rgb(217,217,217)"/>
|
||||
<rect x="390" y="0" width="10" height="1440" fill="rgb(216,216,216)"/>
|
||||
<rect x="400" y="0" width="10" height="1440" fill="rgb(215,215,215)"/>
|
||||
<rect x="410" y="0" width="10" height="1440" fill="rgb(214,214,214)"/>
|
||||
<rect x="420" y="0" width="10" height="1440" fill="rgb(213,213,213)"/>
|
||||
<rect x="430" y="0" width="10" height="1440" fill="rgb(212,212,212)"/>
|
||||
<rect x="440" y="0" width="10" height="1440" fill="rgb(211,211,211)"/>
|
||||
<rect x="450" y="0" width="10" height="1440" fill="rgb(210,210,210)"/>
|
||||
<rect x="460" y="0" width="10" height="1440" fill="rgb(209,209,209)"/>
|
||||
<rect x="470" y="0" width="10" height="1440" fill="rgb(208,208,208)"/>
|
||||
<rect x="480" y="0" width="10" height="1440" fill="rgb(207,207,207)"/>
|
||||
<rect x="490" y="0" width="10" height="1440" fill="rgb(206,206,206)"/>
|
||||
<rect x="500" y="0" width="10" height="1440" fill="rgb(205,205,205)"/>
|
||||
<rect x="510" y="0" width="10" height="1440" fill="rgb(204,204,204)"/>
|
||||
<rect x="520" y="0" width="10" height="1440" fill="rgb(203,203,203)"/>
|
||||
<rect x="530" y="0" width="10" height="1440" fill="rgb(202,202,202)"/>
|
||||
<rect x="540" y="0" width="10" height="1440" fill="rgb(201,201,201)"/>
|
||||
<rect x="550" y="0" width="10" height="1440" fill="rgb(200,200,200)"/>
|
||||
<rect x="560" y="0" width="10" height="1440" fill="rgb(199,199,199)"/>
|
||||
<rect x="570" y="0" width="10" height="1440" fill="rgb(198,198,198)"/>
|
||||
<rect x="580" y="0" width="10" height="1440" fill="rgb(197,197,197)"/>
|
||||
<rect x="590" y="0" width="10" height="1440" fill="rgb(196,196,196)"/>
|
||||
<rect x="600" y="0" width="10" height="1440" fill="rgb(195,195,195)"/>
|
||||
<rect x="610" y="0" width="10" height="1440" fill="rgb(194,194,194)"/>
|
||||
<rect x="620" y="0" width="10" height="1440" fill="rgb(193,193,193)"/>
|
||||
<rect x="630" y="0" width="10" height="1440" fill="rgb(192,192,192)"/>
|
||||
<rect x="640" y="0" width="10" height="1440" fill="rgb(191,191,191)"/>
|
||||
<rect x="650" y="0" width="10" height="1440" fill="rgb(190,190,190)"/>
|
||||
<rect x="660" y="0" width="10" height="1440" fill="rgb(189,189,189)"/>
|
||||
<rect x="670" y="0" width="10" height="1440" fill="rgb(188,188,188)"/>
|
||||
<rect x="680" y="0" width="10" height="1440" fill="rgb(187,187,187)"/>
|
||||
<rect x="690" y="0" width="10" height="1440" fill="rgb(186,186,186)"/>
|
||||
<rect x="700" y="0" width="10" height="1440" fill="rgb(185,185,185)"/>
|
||||
<rect x="710" y="0" width="10" height="1440" fill="rgb(184,184,184)"/>
|
||||
<rect x="720" y="0" width="10" height="1440" fill="rgb(183,183,183)"/>
|
||||
<rect x="730" y="0" width="10" height="1440" fill="rgb(182,182,182)"/>
|
||||
<rect x="740" y="0" width="10" height="1440" fill="rgb(181,181,181)"/>
|
||||
<rect x="750" y="0" width="10" height="1440" fill="rgb(180,180,180)"/>
|
||||
<rect x="760" y="0" width="10" height="1440" fill="rgb(179,179,179)"/>
|
||||
<rect x="770" y="0" width="10" height="1440" fill="rgb(178,178,178)"/>
|
||||
<rect x="780" y="0" width="10" height="1440" fill="rgb(177,177,177)"/>
|
||||
<rect x="790" y="0" width="10" height="1440" fill="rgb(176,176,176)"/>
|
||||
<rect x="800" y="0" width="10" height="1440" fill="rgb(175,175,175)"/>
|
||||
<rect x="810" y="0" width="10" height="1440" fill="rgb(174,174,174)"/>
|
||||
<rect x="820" y="0" width="10" height="1440" fill="rgb(173,173,173)"/>
|
||||
<rect x="830" y="0" width="10" height="1440" fill="rgb(172,172,172)"/>
|
||||
<rect x="840" y="0" width="10" height="1440" fill="rgb(171,171,171)"/>
|
||||
<rect x="850" y="0" width="10" height="1440" fill="rgb(170,170,170)"/>
|
||||
<rect x="860" y="0" width="10" height="1440" fill="rgb(169,169,169)"/>
|
||||
<rect x="870" y="0" width="10" height="1440" fill="rgb(168,168,168)"/>
|
||||
<rect x="880" y="0" width="10" height="1440" fill="rgb(167,167,167)"/>
|
||||
<rect x="890" y="0" width="10" height="1440" fill="rgb(166,166,166)"/>
|
||||
<rect x="900" y="0" width="10" height="1440" fill="rgb(165,165,165)"/>
|
||||
<rect x="910" y="0" width="10" height="1440" fill="rgb(164,164,164)"/>
|
||||
<rect x="920" y="0" width="10" height="1440" fill="rgb(163,163,163)"/>
|
||||
<rect x="930" y="0" width="10" height="1440" fill="rgb(162,162,162)"/>
|
||||
<rect x="940" y="0" width="10" height="1440" fill="rgb(161,161,161)"/>
|
||||
<rect x="950" y="0" width="10" height="1440" fill="rgb(160,160,160)"/>
|
||||
<rect x="960" y="0" width="10" height="1440" fill="rgb(159,159,159)"/>
|
||||
<rect x="970" y="0" width="10" height="1440" fill="rgb(158,158,158)"/>
|
||||
<rect x="980" y="0" width="10" height="1440" fill="rgb(157,157,157)"/>
|
||||
<rect x="990" y="0" width="10" height="1440" fill="rgb(156,156,156)"/>
|
||||
<rect x="1000" y="0" width="10" height="1440" fill="rgb(155,155,155)"/>
|
||||
<rect x="1010" y="0" width="10" height="1440" fill="rgb(154,154,154)"/>
|
||||
<rect x="1020" y="0" width="10" height="1440" fill="rgb(153,153,153)"/>
|
||||
<rect x="1030" y="0" width="10" height="1440" fill="rgb(152,152,152)"/>
|
||||
<rect x="1040" y="0" width="10" height="1440" fill="rgb(151,151,151)"/>
|
||||
<rect x="1050" y="0" width="10" height="1440" fill="rgb(150,150,150)"/>
|
||||
<rect x="1060" y="0" width="10" height="1440" fill="rgb(149,149,149)"/>
|
||||
<rect x="1070" y="0" width="10" height="1440" fill="rgb(148,148,148)"/>
|
||||
<rect x="1080" y="0" width="10" height="1440" fill="rgb(147,147,147)"/>
|
||||
<rect x="1090" y="0" width="10" height="1440" fill="rgb(146,146,146)"/>
|
||||
<rect x="1100" y="0" width="10" height="1440" fill="rgb(145,145,145)"/>
|
||||
<rect x="1110" y="0" width="10" height="1440" fill="rgb(144,144,144)"/>
|
||||
<rect x="1120" y="0" width="10" height="1440" fill="rgb(143,143,143)"/>
|
||||
<rect x="1130" y="0" width="10" height="1440" fill="rgb(142,142,142)"/>
|
||||
<rect x="1140" y="0" width="10" height="1440" fill="rgb(141,141,141)"/>
|
||||
<rect x="1150" y="0" width="10" height="1440" fill="rgb(140,140,140)"/>
|
||||
<rect x="1160" y="0" width="10" height="1440" fill="rgb(139,139,139)"/>
|
||||
<rect x="1170" y="0" width="10" height="1440" fill="rgb(138,138,138)"/>
|
||||
<rect x="1180" y="0" width="10" height="1440" fill="rgb(137,137,137)"/>
|
||||
<rect x="1190" y="0" width="10" height="1440" fill="rgb(136,136,136)"/>
|
||||
<rect x="1200" y="0" width="10" height="1440" fill="rgb(135,135,135)"/>
|
||||
<rect x="1210" y="0" width="10" height="1440" fill="rgb(134,134,134)"/>
|
||||
<rect x="1220" y="0" width="10" height="1440" fill="rgb(133,133,133)"/>
|
||||
<rect x="1230" y="0" width="10" height="1440" fill="rgb(132,132,132)"/>
|
||||
<rect x="1240" y="0" width="10" height="1440" fill="rgb(131,131,131)"/>
|
||||
<rect x="1250" y="0" width="10" height="1440" fill="rgb(130,130,130)"/>
|
||||
<rect x="1260" y="0" width="10" height="1440" fill="rgb(129,129,129)"/>
|
||||
<rect x="1270" y="0" width="10" height="1440" fill="rgb(128,128,128)"/>
|
||||
<rect x="1280" y="0" width="10" height="1440" fill="rgb(127,127,127)"/>
|
||||
<rect x="1290" y="0" width="10" height="1440" fill="rgb(126,126,126)"/>
|
||||
<rect x="1300" y="0" width="10" height="1440" fill="rgb(125,125,125)"/>
|
||||
<rect x="1310" y="0" width="10" height="1440" fill="rgb(124,124,124)"/>
|
||||
<rect x="1320" y="0" width="10" height="1440" fill="rgb(123,123,123)"/>
|
||||
<rect x="1330" y="0" width="10" height="1440" fill="rgb(122,122,122)"/>
|
||||
<rect x="1340" y="0" width="10" height="1440" fill="rgb(121,121,121)"/>
|
||||
<rect x="1350" y="0" width="10" height="1440" fill="rgb(120,120,120)"/>
|
||||
<rect x="1360" y="0" width="10" height="1440" fill="rgb(119,119,119)"/>
|
||||
<rect x="1370" y="0" width="10" height="1440" fill="rgb(118,118,118)"/>
|
||||
<rect x="1380" y="0" width="10" height="1440" fill="rgb(117,117,117)"/>
|
||||
<rect x="1390" y="0" width="10" height="1440" fill="rgb(116,116,116)"/>
|
||||
<rect x="1400" y="0" width="10" height="1440" fill="rgb(115,115,115)"/>
|
||||
<rect x="1410" y="0" width="10" height="1440" fill="rgb(114,114,114)"/>
|
||||
<rect x="1420" y="0" width="10" height="1440" fill="rgb(113,113,113)"/>
|
||||
<rect x="1430" y="0" width="10" height="1440" fill="rgb(112,112,112)"/>
|
||||
<rect x="1440" y="0" width="10" height="1440" fill="rgb(111,111,111)"/>
|
||||
<rect x="1450" y="0" width="10" height="1440" fill="rgb(110,110,110)"/>
|
||||
<rect x="1460" y="0" width="10" height="1440" fill="rgb(109,109,109)"/>
|
||||
<rect x="1470" y="0" width="10" height="1440" fill="rgb(108,108,108)"/>
|
||||
<rect x="1480" y="0" width="10" height="1440" fill="rgb(107,107,107)"/>
|
||||
<rect x="1490" y="0" width="10" height="1440" fill="rgb(106,106,106)"/>
|
||||
<rect x="1500" y="0" width="10" height="1440" fill="rgb(105,105,105)"/>
|
||||
<rect x="1510" y="0" width="10" height="1440" fill="rgb(104,104,104)"/>
|
||||
<rect x="1520" y="0" width="10" height="1440" fill="rgb(103,103,103)"/>
|
||||
<rect x="1530" y="0" width="10" height="1440" fill="rgb(102,102,102)"/>
|
||||
<rect x="1540" y="0" width="10" height="1440" fill="rgb(101,101,101)"/>
|
||||
<rect x="1550" y="0" width="10" height="1440" fill="rgb(100,100,100)"/>
|
||||
<rect x="1560" y="0" width="10" height="1440" fill="rgb(99,99,99)"/>
|
||||
<rect x="1570" y="0" width="10" height="1440" fill="rgb(98,98,98)"/>
|
||||
<rect x="1580" y="0" width="10" height="1440" fill="rgb(97,97,97)"/>
|
||||
<rect x="1590" y="0" width="10" height="1440" fill="rgb(96,96,96)"/>
|
||||
<rect x="1600" y="0" width="10" height="1440" fill="rgb(95,95,95)"/>
|
||||
<rect x="1610" y="0" width="10" height="1440" fill="rgb(94,94,94)"/>
|
||||
<rect x="1620" y="0" width="10" height="1440" fill="rgb(93,93,93)"/>
|
||||
<rect x="1630" y="0" width="10" height="1440" fill="rgb(92,92,92)"/>
|
||||
<rect x="1640" y="0" width="10" height="1440" fill="rgb(91,91,91)"/>
|
||||
<rect x="1650" y="0" width="10" height="1440" fill="rgb(90,90,90)"/>
|
||||
<rect x="1660" y="0" width="10" height="1440" fill="rgb(89,89,89)"/>
|
||||
<rect x="1670" y="0" width="10" height="1440" fill="rgb(88,88,88)"/>
|
||||
<rect x="1680" y="0" width="10" height="1440" fill="rgb(87,87,87)"/>
|
||||
<rect x="1690" y="0" width="10" height="1440" fill="rgb(86,86,86)"/>
|
||||
<rect x="1700" y="0" width="10" height="1440" fill="rgb(85,85,85)"/>
|
||||
<rect x="1710" y="0" width="10" height="1440" fill="rgb(84,84,84)"/>
|
||||
<rect x="1720" y="0" width="10" height="1440" fill="rgb(83,83,83)"/>
|
||||
<rect x="1730" y="0" width="10" height="1440" fill="rgb(82,82,82)"/>
|
||||
<rect x="1740" y="0" width="10" height="1440" fill="rgb(81,81,81)"/>
|
||||
<rect x="1750" y="0" width="10" height="1440" fill="rgb(80,80,80)"/>
|
||||
<rect x="1760" y="0" width="10" height="1440" fill="rgb(79,79,79)"/>
|
||||
<rect x="1770" y="0" width="10" height="1440" fill="rgb(78,78,78)"/>
|
||||
<rect x="1780" y="0" width="10" height="1440" fill="rgb(77,77,77)"/>
|
||||
<rect x="1790" y="0" width="10" height="1440" fill="rgb(76,76,76)"/>
|
||||
<rect x="1800" y="0" width="10" height="1440" fill="rgb(75,75,75)"/>
|
||||
<rect x="1810" y="0" width="10" height="1440" fill="rgb(74,74,74)"/>
|
||||
<rect x="1820" y="0" width="10" height="1440" fill="rgb(73,73,73)"/>
|
||||
<rect x="1830" y="0" width="10" height="1440" fill="rgb(72,72,72)"/>
|
||||
<rect x="1840" y="0" width="10" height="1440" fill="rgb(71,71,71)"/>
|
||||
<rect x="1850" y="0" width="10" height="1440" fill="rgb(70,70,70)"/>
|
||||
<rect x="1860" y="0" width="10" height="1440" fill="rgb(69,69,69)"/>
|
||||
<rect x="1870" y="0" width="10" height="1440" fill="rgb(68,68,68)"/>
|
||||
<rect x="1880" y="0" width="10" height="1440" fill="rgb(67,67,67)"/>
|
||||
<rect x="1890" y="0" width="10" height="1440" fill="rgb(66,66,66)"/>
|
||||
<rect x="1900" y="0" width="10" height="1440" fill="rgb(65,65,65)"/>
|
||||
<rect x="1910" y="0" width="10" height="1440" fill="rgb(64,64,64)"/>
|
||||
<rect x="1920" y="0" width="10" height="1440" fill="rgb(63,63,63)"/>
|
||||
<rect x="1930" y="0" width="10" height="1440" fill="rgb(62,62,62)"/>
|
||||
<rect x="1940" y="0" width="10" height="1440" fill="rgb(61,61,61)"/>
|
||||
<rect x="1950" y="0" width="10" height="1440" fill="rgb(60,60,60)"/>
|
||||
<rect x="1960" y="0" width="10" height="1440" fill="rgb(59,59,59)"/>
|
||||
<rect x="1970" y="0" width="10" height="1440" fill="rgb(58,58,58)"/>
|
||||
<rect x="1980" y="0" width="10" height="1440" fill="rgb(57,57,57)"/>
|
||||
<rect x="1990" y="0" width="10" height="1440" fill="rgb(56,56,56)"/>
|
||||
<rect x="2000" y="0" width="10" height="1440" fill="rgb(55,55,55)"/>
|
||||
<rect x="2010" y="0" width="10" height="1440" fill="rgb(54,54,54)"/>
|
||||
<rect x="2020" y="0" width="10" height="1440" fill="rgb(53,53,53)"/>
|
||||
<rect x="2030" y="0" width="10" height="1440" fill="rgb(52,52,52)"/>
|
||||
<rect x="2040" y="0" width="10" height="1440" fill="rgb(51,51,51)"/>
|
||||
<rect x="2050" y="0" width="10" height="1440" fill="rgb(50,50,50)"/>
|
||||
<rect x="2060" y="0" width="10" height="1440" fill="rgb(49,49,49)"/>
|
||||
<rect x="2070" y="0" width="10" height="1440" fill="rgb(48,48,48)"/>
|
||||
<rect x="2080" y="0" width="10" height="1440" fill="rgb(47,47,47)"/>
|
||||
<rect x="2090" y="0" width="10" height="1440" fill="rgb(46,46,46)"/>
|
||||
<rect x="2100" y="0" width="10" height="1440" fill="rgb(45,45,45)"/>
|
||||
<rect x="2110" y="0" width="10" height="1440" fill="rgb(44,44,44)"/>
|
||||
<rect x="2120" y="0" width="10" height="1440" fill="rgb(43,43,43)"/>
|
||||
<rect x="2130" y="0" width="10" height="1440" fill="rgb(42,42,42)"/>
|
||||
<rect x="2140" y="0" width="10" height="1440" fill="rgb(41,41,41)"/>
|
||||
<rect x="2150" y="0" width="10" height="1440" fill="rgb(40,40,40)"/>
|
||||
<rect x="2160" y="0" width="10" height="1440" fill="rgb(39,39,39)"/>
|
||||
<rect x="2170" y="0" width="10" height="1440" fill="rgb(38,38,38)"/>
|
||||
<rect x="2180" y="0" width="10" height="1440" fill="rgb(37,37,37)"/>
|
||||
<rect x="2190" y="0" width="10" height="1440" fill="rgb(36,36,36)"/>
|
||||
<rect x="2200" y="0" width="10" height="1440" fill="rgb(35,35,35)"/>
|
||||
<rect x="2210" y="0" width="10" height="1440" fill="rgb(34,34,34)"/>
|
||||
<rect x="2220" y="0" width="10" height="1440" fill="rgb(33,33,33)"/>
|
||||
<rect x="2230" y="0" width="10" height="1440" fill="rgb(32,32,32)"/>
|
||||
<rect x="2240" y="0" width="10" height="1440" fill="rgb(31,31,31)"/>
|
||||
<rect x="2250" y="0" width="10" height="1440" fill="rgb(30,30,30)"/>
|
||||
<rect x="2260" y="0" width="10" height="1440" fill="rgb(29,29,29)"/>
|
||||
<rect x="2270" y="0" width="10" height="1440" fill="rgb(28,28,28)"/>
|
||||
<rect x="2280" y="0" width="10" height="1440" fill="rgb(27,27,27)"/>
|
||||
<rect x="2290" y="0" width="10" height="1440" fill="rgb(26,26,26)"/>
|
||||
<rect x="2300" y="0" width="10" height="1440" fill="rgb(25,25,25)"/>
|
||||
<rect x="2310" y="0" width="10" height="1440" fill="rgb(24,24,24)"/>
|
||||
<rect x="2320" y="0" width="10" height="1440" fill="rgb(23,23,23)"/>
|
||||
<rect x="2330" y="0" width="10" height="1440" fill="rgb(22,22,22)"/>
|
||||
<rect x="2340" y="0" width="10" height="1440" fill="rgb(21,21,21)"/>
|
||||
<rect x="2350" y="0" width="10" height="1440" fill="rgb(20,20,20)"/>
|
||||
<rect x="2360" y="0" width="10" height="1440" fill="rgb(19,19,19)"/>
|
||||
<rect x="2370" y="0" width="10" height="1440" fill="rgb(18,18,18)"/>
|
||||
<rect x="2380" y="0" width="10" height="1440" fill="rgb(17,17,17)"/>
|
||||
<rect x="2390" y="0" width="10" height="1440" fill="rgb(16,16,16)"/>
|
||||
<rect x="2400" y="0" width="10" height="1440" fill="rgb(15,15,15)"/>
|
||||
<rect x="2410" y="0" width="10" height="1440" fill="rgb(14,14,14)"/>
|
||||
<rect x="2420" y="0" width="10" height="1440" fill="rgb(13,13,13)"/>
|
||||
<rect x="2430" y="0" width="10" height="1440" fill="rgb(12,12,12)"/>
|
||||
<rect x="2440" y="0" width="10" height="1440" fill="rgb(11,11,11)"/>
|
||||
<rect x="2450" y="0" width="10" height="1440" fill="rgb(10,10,10)"/>
|
||||
<rect x="2460" y="0" width="10" height="1440" fill="rgb(9,9,9)"/>
|
||||
<rect x="2470" y="0" width="10" height="1440" fill="rgb(8,8,8)"/>
|
||||
<rect x="2480" y="0" width="10" height="1440" fill="rgb(7,7,7)"/>
|
||||
<rect x="2490" y="0" width="10" height="1440" fill="rgb(6,6,6)"/>
|
||||
<rect x="2500" y="0" width="10" height="1440" fill="rgb(5,5,5)"/>
|
||||
<rect x="2510" y="0" width="10" height="1440" fill="rgb(4,4,4)"/>
|
||||
<rect x="2520" y="0" width="10" height="1440" fill="rgb(3,3,3)"/>
|
||||
<rect x="2530" y="0" width="10" height="1440" fill="rgb(2,2,2)"/>
|
||||
<rect x="2540" y="0" width="10" height="1440" fill="rgb(1,1,1)"/>
|
||||
<rect x="2550" y="0" width="10" height="1440" fill="rgb(0,0,0)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 18 KiB |
@@ -0,0 +1,53 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1920 1080">
|
||||
<rect width="1920" height="1080" fill="#ffffff"/>
|
||||
<text x="960.0" y="100" text-anchor="middle" font-family="sans-serif" font-size="54" fill="#1a1a2e" font-weight="bold">Zoom: die 16 hellsten Abstufungen</text>
|
||||
<rect x="60.00" y="220" width="101.25" height="500" fill="rgb(255,255,255)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="110.62" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">255</text>
|
||||
<text x="110.62" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xFF</text>
|
||||
<rect x="173.25" y="220" width="101.25" height="500" fill="rgb(254,254,254)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="223.88" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">254</text>
|
||||
<text x="223.88" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xFE</text>
|
||||
<rect x="286.50" y="220" width="101.25" height="500" fill="rgb(253,253,253)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="337.12" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">253</text>
|
||||
<text x="337.12" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xFD</text>
|
||||
<rect x="399.75" y="220" width="101.25" height="500" fill="rgb(252,252,252)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="450.38" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">252</text>
|
||||
<text x="450.38" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xFC</text>
|
||||
<rect x="513.00" y="220" width="101.25" height="500" fill="rgb(251,251,251)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="563.62" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">251</text>
|
||||
<text x="563.62" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xFB</text>
|
||||
<rect x="626.25" y="220" width="101.25" height="500" fill="rgb(250,250,250)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="676.88" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">250</text>
|
||||
<text x="676.88" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xFA</text>
|
||||
<rect x="739.50" y="220" width="101.25" height="500" fill="rgb(249,249,249)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="790.12" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">249</text>
|
||||
<text x="790.12" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF9</text>
|
||||
<rect x="852.75" y="220" width="101.25" height="500" fill="rgb(248,248,248)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="903.38" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">248</text>
|
||||
<text x="903.38" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF8</text>
|
||||
<rect x="966.00" y="220" width="101.25" height="500" fill="rgb(247,247,247)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1016.62" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">247</text>
|
||||
<text x="1016.62" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF7</text>
|
||||
<rect x="1079.25" y="220" width="101.25" height="500" fill="rgb(246,246,246)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1129.88" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">246</text>
|
||||
<text x="1129.88" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF6</text>
|
||||
<rect x="1192.50" y="220" width="101.25" height="500" fill="rgb(245,245,245)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1243.12" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">245</text>
|
||||
<text x="1243.12" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF5</text>
|
||||
<rect x="1305.75" y="220" width="101.25" height="500" fill="rgb(244,244,244)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1356.38" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">244</text>
|
||||
<text x="1356.38" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF4</text>
|
||||
<rect x="1419.00" y="220" width="101.25" height="500" fill="rgb(243,243,243)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1469.62" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">243</text>
|
||||
<text x="1469.62" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF3</text>
|
||||
<rect x="1532.25" y="220" width="101.25" height="500" fill="rgb(242,242,242)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1582.88" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">242</text>
|
||||
<text x="1582.88" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF2</text>
|
||||
<rect x="1645.50" y="220" width="101.25" height="500" fill="rgb(241,241,241)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1696.12" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">241</text>
|
||||
<text x="1696.12" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF1</text>
|
||||
<rect x="1758.75" y="220" width="101.25" height="500" fill="rgb(240,240,240)" stroke="#1a1a2e" stroke-width="3"/>
|
||||
<text x="1809.38" y="820" text-anchor="middle" font-family="monospace" font-size="42" fill="#1a1a2e" font-weight="bold">240</text>
|
||||
<text x="1809.38" y="900" text-anchor="middle" font-family="monospace" font-size="36" fill="#4a4a6a">0xF0</text>
|
||||
<text x="960.0" y="1020" text-anchor="middle" font-family="sans-serif" font-size="28" fill="#4a4a6a" font-style="italic">jede Stufe = Unterschied von 1/255 ≈ 0,4% Helligkeit</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 198 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 68 KiB |
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Dateiformate, Schnittstellen, Speichermedien & Distributionswege (223015b)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Dateiformate, Schnittstellen, Speichermedien & Distributionswege
|
||||
---
|
||||
<style>
|
||||
@@ -92,6 +92,8 @@ section.aufgabe footer {
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015b/](https://librete.ch/hdm/223015b/)
|
||||
|
||||
---
|
||||
@@ -110,7 +112,7 @@ Hochschule der Medien Stuttgart
|
||||
| **Formate** | ZIP, PNG, FLAC, GIF | JPEG, MP3, H.264/H.265 |
|
||||
|
||||
**Faustregel:**
|
||||
- Medien für Endnutzer → Lossy oft akzeptabel
|
||||
- Medien für EndnutzerInnen → Lossy oft akzeptabel
|
||||
- Quellmaterial, Code, Archive → Lossless nötig
|
||||
|
||||
<!--
|
||||
@@ -208,13 +210,13 @@ VERGLEICH: SSD ~$50/TB, HDD ~$15/TB, LTO ~$5/TB
|
||||
### Distribution: physisch (Kauf, Verleih, Kopie)
|
||||
|
||||
- **Text**
|
||||
- Bücher, Zeitungen, Zeitschriften, Lochkarten
|
||||
- Bücher, Zeitungen, Zeitschriften, Lochkarten
|
||||
- **Bild**
|
||||
- Fotografie (Negativ, Dia, Polaroid), Mikrofilm
|
||||
- Fotografie (Negativ, Dia, Polaroid), Mikrofilm
|
||||
- **Audio:**
|
||||
- Schallplatte (Vinyl, Schellack), Tonband, Musikkassette
|
||||
- Schallplatte (Vinyl, Schellack), Tonband, Musikkassette
|
||||
- **Video:**
|
||||
- Film (35mm, Super 8), VHS, Betamax
|
||||
- Film (35mm, Super 8), VHS, Betamax
|
||||
|
||||
|
||||
---
|
||||
@@ -227,13 +229,13 @@ VERGLEICH: SSD ~$50/TB, HDD ~$15/TB, LTO ~$5/TB
|
||||
### Distribution: Datenträger (CD, USB), Download, Streaming, P2P
|
||||
|
||||
- **Text**
|
||||
- E-Book (PDF, EPUB), Dokumente (TXT, DOCX)
|
||||
- E-Book (PDF, EPUB), Dokumente (TXT, DOCX)
|
||||
- **Bild**
|
||||
- Digitalfoto (JPEG, PNG, RAW, WebP, GIF)
|
||||
- Digitalfoto (JPEG, PNG, RAW, WebP, GIF)
|
||||
- **Audio**
|
||||
- Audiodatei (MP3, FLAC, WAV, AAC, OGG)
|
||||
- Audiodatei (MP3, FLAC, WAV, AAC, OGG)
|
||||
- **Video**
|
||||
- Videodatei (MP4, MKV, AVI, WebM)
|
||||
- Videodatei (MP4, MKV, AVI, WebM)
|
||||
|
||||
|
||||
---
|
||||
@@ -245,13 +247,13 @@ VERGLEICH: SSD ~$50/TB, HDD ~$15/TB, LTO ~$5/TB
|
||||
# Digitale Speichermedien
|
||||
|
||||
- **Optische Speicher**
|
||||
- CD, DVD, Blu-ray
|
||||
- CD, DVD, Blu-ray
|
||||
- **Magnetische Speicher**
|
||||
- Festplatte (HDD), Magnetband (LTO)
|
||||
- Festplatte (HDD), Magnetband (LTO)
|
||||
- **Flash-Speicher**
|
||||
- SSD, USB-Stick, SD-Karte
|
||||
- SSD, USB-Stick, SD-Karte
|
||||
- **Cloud-Speicher**
|
||||
- Dropbox, Google Drive, iCloud, AWS S3
|
||||
- Dropbox, Google Drive, iCloud, AWS S3
|
||||
|
||||
|
||||
---
|
||||
@@ -277,14 +279,12 @@ Breite × Höhe × Farbtiefe (in Bytes)
|
||||
| 32 | 16,7 Mio. + Alpha | Transparenz |
|
||||
|
||||
<!--
|
||||
BERECHNUNG: Breite × Höhe × (Farbtiefe / 8)
|
||||
BEISPIEL: 1920×1080 × 24 Bit = 1920×1080×3 = 6.220.800 Bytes ≈ 6,2 MB
|
||||
|
||||
Farbtiefe erklärt:
|
||||
- 1 Bit: 2^1 = 2 Farben
|
||||
- 8 Bit: 2^8 = 256 Farben
|
||||
- 24 Bit: 2^24 = 16.777.216 Farben (je 8 Bit für R, G, B)
|
||||
- 32 Bit: 24 Bit + 8 Bit Alpha-Kanal
|
||||
KLAUSURRELEVANT:
|
||||
- Formel: Breite × Höhe × (Farbtiefe / 8) = Bytes
|
||||
- Beispielrechnung: 1920 × 1080 × 3 = 6.220.800 Bytes ≈ 6,2 MB
|
||||
- Farbtiefe: 2^n Farben bei n Bit
|
||||
- 24 Bit = 8 Bit pro Kanal (R, G, B)
|
||||
- 32 Bit = 24 Bit + 8 Bit Alpha (Transparenz)
|
||||
-->
|
||||
|
||||
|
||||
@@ -306,17 +306,15 @@ Farbtiefe erklärt:
|
||||
<circle cx="50" cy="50" r="40" fill="#ff0000"/>
|
||||
```
|
||||
|
||||
<small>SVG beschreibt nicht jeden einzelnen Pixel im Raster, sondern deklariert wie Farben und Formen gesetzt werden.</small>
|
||||
<small>SVG beschreibt WAS gezeichnet werden soll, nicht WIE jeder Pixel aussieht.</small>
|
||||
|
||||
<!--
|
||||
Vektorgrafiken beschreiben WAS gezeichnet werden soll.
|
||||
Rastergrafiken beschreiben WIE jeder Pixel aussieht.
|
||||
|
||||
Rendering-Pipeline:
|
||||
Vektordaten → Rasterisierung → Framebuffer → Display
|
||||
|
||||
Beim Skalieren werden einfach die Koordinaten multipliziert.
|
||||
Keine Information geht verloren.
|
||||
KLAUSURRELEVANT:
|
||||
- Vektor = Beschreibung (deklarativ)
|
||||
- Raster = Pixel für Pixel (imperativ)
|
||||
- Rendering-Pipeline: Vektordaten → Rasterisierung → Display
|
||||
- Skalierung = Koordinaten multiplizieren → keine Information geht verloren
|
||||
- SVG = Scalable Vector Graphics (Web-Standard)
|
||||
-->
|
||||
|
||||
|
||||
@@ -334,18 +332,17 @@ Keine Information geht verloren.
|
||||
- Niedrige Frequenzen besser als hohe
|
||||
|
||||
**JPEG nutzt das aus:**
|
||||
- Farbauflösung reduzieren (aber Helligkeit behalten)
|
||||
- Farbauflösung reduzieren (Helligkeit behalten)
|
||||
- Glatte Flächen effizient speichern
|
||||
- Hohe Frequenzen (Details) verwerfen
|
||||
- Hohe Frequenzen (feine Details) verwerfen
|
||||
|
||||
<!--
|
||||
Das ist die visuelle Entsprechung zur Psychoakustik.
|
||||
|
||||
Das Auge hat mehr Rezeptoren für Helligkeit (Stäbchen)
|
||||
als für Farbe (Zapfen).
|
||||
|
||||
Hohe Frequenzen = schnelle Wechsel = feine Details
|
||||
Niedrige Frequenzen = langsame Wechsel = große Flächen
|
||||
KLAUSURRELEVANT:
|
||||
- Mehr Stäbchen (Helligkeit) als Zapfen (Farbe) im Auge
|
||||
- "Frequenz" = räumliche Frequenz = wie schnell ändert sich Helligkeit?
|
||||
- Niedrig = langsame Änderung = große gleichmäßige Fläche
|
||||
- Hoch = schnelle Änderung = feine Details, Kanten
|
||||
- Analogie zur Psychoakustik bei MP3 (letztes Mal)
|
||||
-->
|
||||
|
||||
|
||||
@@ -357,24 +354,25 @@ Niedrige Frequenzen = langsame Wechsel = große Flächen
|
||||
|
||||

|
||||
|
||||
# JPEG: Schritt 1 – Farbraumkonversion
|
||||
# JPEG Schritt 1: Farbraumkonversion
|
||||
|
||||
**RGB → Y'CbCr** (seltener Y'UV)
|
||||
**RGB → Y'CbCr**
|
||||
|
||||
- **Y** = Helligkeit (Luminanz) – Was das Auge am besten sieht
|
||||
- **Y** = Helligkeit (Luminanz)
|
||||
- **Cb** = Blau-Gelb-Anteil (Chrominanz)
|
||||
- **Cr** = Rot-Grün-Anteil (Chrominanz)
|
||||
|
||||
**Warum diese Trennung?**
|
||||
Y (Helligkeit) behält volle Auflösung.
|
||||
Cb/Cr (Farbe) kann reduziert werden – Auge merkt es kaum.
|
||||
**Warum?**
|
||||
Y (Helligkeit) behält volle Auflösung
|
||||
Cb/Cr (Farbe) kann reduziert werden
|
||||
|
||||
<!--
|
||||
YCbCr ist wie RGB ein Tripel aus 3 Werten pro Pixel.
|
||||
Der Unterschied: Statt Rot-Grün-Blau speichern wir Helligkeit + 2 Farbdifferenzen.
|
||||
|
||||
Die Umrechnung ist reversibel (mathematische Transformation).
|
||||
Der Clou: Jetzt können wir Helligkeit und Farbe getrennt behandeln.
|
||||
KLAUSURRELEVANT:
|
||||
- YCbCr = auch 3 Werte pro Pixel, aber anders organisiert
|
||||
- Statt R-G-B: Helligkeit + 2 Farbdifferenzen
|
||||
- Umrechnung ist reversibel (mathematische Transformation)
|
||||
- Vorteil: Helligkeit und Farbe getrennt behandelbar
|
||||
- Bild zeigt: Y (oben), Cb (Mitte), Cr (unten)
|
||||
-->
|
||||
|
||||
|
||||
@@ -384,14 +382,14 @@ Der Clou: Jetzt können wir Helligkeit und Farbe getrennt behandeln.
|
||||
<!-- _footer: "" -->
|
||||
|
||||
|
||||
# JPEG: Schritt 6 – Huffman-Coding
|
||||
# JPEG Schritt 6: Huffman-Coding
|
||||
|
||||
**Verlustfreie Kompression der Restwerte**
|
||||
|
||||
**Idee:** Statt fester 8 Bit pro Wert → variable Bitlänge
|
||||
Häufige Werte bekommen kurze Bit-Sequenzen.
|
||||
**Idee:** Variable Bitlänge statt fester 8 Bit
|
||||
Häufige Werte → kurze Codes
|
||||
|
||||
| Zeichen | Häufigkeit | Code (Bit-Sequenz) |
|
||||
| Zeichen | Häufigkeit | Code |
|
||||
|---------|------------|------|
|
||||
| e | 40% | `0` (1 Bit) |
|
||||
| a | 25% | `10` (2 Bit) |
|
||||
@@ -400,9 +398,74 @@ Häufige Werte bekommen kurze Bit-Sequenzen.
|
||||
| u | 5% | `1111` (4 Bit) |
|
||||
|
||||
<!--
|
||||
Huffman-Coding ist verlustfrei.
|
||||
Der "Code" ist eine Bit-Sequenz, die das Zeichen eindeutig identifiziert.
|
||||
Weil "e" am häufigsten vorkommt, bekommt es den kürzesten Code.
|
||||
KLAUSURRELEVANT:
|
||||
- Huffman = verlustfrei, optimal für bekannte Häufigkeiten
|
||||
- Präfix-frei: Kein Code ist Anfang eines anderen
|
||||
- Häufigstes Zeichen = kürzester Code
|
||||
- Auch in ZIP, PNG, MP3 verwendet
|
||||
-->
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: "" -->
|
||||
<!-- _footer: "" -->
|
||||
|
||||
<!--
|
||||
# Huffman-Coding: Beispiel
|
||||
|
||||
**Originaltext:** `ABRACADABRA` (11 Zeichen × 8 Bit = 88 Bit)
|
||||
|
||||
**Häufigkeitsanalyse:**
|
||||
A=5, B=2, R=2, C=1, D=1
|
||||
|
||||
**Huffman-Baum → Codes:**
|
||||
| Zeichen | Häufigkeit | Code |
|
||||
|---------|------------|------|
|
||||
| A | 5 | `0` |
|
||||
| B | 2 | `10` |
|
||||
| R | 2 | `110` |
|
||||
| C | 1 | `1110` |
|
||||
| D | 1 | `1111` |
|
||||
|
||||
**Codiert:** `0 10 110 0 1110 0 1111 0 10 110 0` = **23 Bit**
|
||||
**Kompression:** 88 → 23 Bit = **74% gespart**
|
||||
|
||||
|
||||
- Beispiel Schritt für Schritt durchrechnen
|
||||
- Warum funktioniert's? A kommt 5× vor, bekommt kürzesten Code
|
||||
- Präfix-Eigenschaft: Kein Code ist Anfang eines anderen → eindeutig dekodierbar
|
||||
- Frage: "Was passiert, wenn alle Zeichen gleich häufig sind?" → Keine Ersparnis
|
||||
- In JPEG: Nicht Buchstaben, sondern DCT-Koeffizienten werden so codiert
|
||||
-->
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: "" -->
|
||||
<!-- _footer: "" -->
|
||||
|
||||
|
||||
# WebP & AVIF: Moderne Alternativen
|
||||
|
||||
**WebP (Google, 2010):**
|
||||
- Lossy und Lossless
|
||||
- Transparenz und Animationen
|
||||
- 25–35% kleiner als JPEG
|
||||
|
||||
**AVIF (2019):**
|
||||
- Basiert auf AV1-Video-Codec
|
||||
- 50% kleiner als JPEG
|
||||
- HDR-Unterstützung, patent-frei
|
||||
|
||||
**Browser-Support 2025:** WebP universell, AVIF wächst
|
||||
|
||||
<!--
|
||||
KLAUSURRELEVANT:
|
||||
- WebP: VP8-Kompression (Google Video-Codec)
|
||||
- AVIF: Alliance for Open Media (Google, Netflix, Amazon, Apple, Mozilla)
|
||||
- Beide besser als JPEG, aber Kompatibilität bleibt Problem
|
||||
- JPEG bleibt dominant: alte Kameras, Software, Workflows
|
||||
-->
|
||||
|
||||
|
||||
@@ -414,28 +477,22 @@ Weil "e" am häufigsten vorkommt, bekommt es den kürzesten Code.
|
||||
|
||||
# Container und Codec
|
||||
|
||||
**Container = Das Dateiformat (Beispiel: MP4)**
|
||||
**Container = Dateiformat (z.B. MP4)**
|
||||
Die "Box", die verschiedene Streams zusammenpackt:
|
||||
- Video-Stream
|
||||
- Audio-Stream(s)
|
||||
- Untertitel
|
||||
- Metadaten
|
||||
|
||||
**Codec = Der Kompressionsalgorithmus (Beispiel: AV1)**
|
||||
Entscheidet, WIE komprimiert wird.
|
||||
|
||||
**Codec = Kompressionsalgorithmus (z.B. H.264)**
|
||||
Bestimmt, WIE komprimiert wird
|
||||
|
||||
<!--
|
||||
Container ≠ Codec
|
||||
Das ist ein häufiges Missverständnis.
|
||||
|
||||
MP4 ist ein Container, nicht ein Codec.
|
||||
Ein MP4 kann H.264, H.265 oder AV1 enthalten.
|
||||
|
||||
Übrigens: JPEG ist ein Codec (für Bilder), kein Container.
|
||||
Bei Bildern fallen Container und Codec oft zusammen.
|
||||
|
||||
Tools wie MediaInfo zeigen beide Informationen.
|
||||
KLAUSURRELEVANT:
|
||||
- Container ≠ Codec (häufiges Missverständnis!)
|
||||
- MP4 kann H.264, H.265 oder AV1 enthalten
|
||||
- Gleiche Endung, unterschiedlicher Inhalt
|
||||
- Tool-Tipp: MediaInfo zeigt beides an
|
||||
-->
|
||||
|
||||
|
||||
@@ -451,19 +508,19 @@ Tools wie MediaInfo zeigen beide Informationen.
|
||||
|
||||
**Warum dominant?**
|
||||
- Exzellente Kompression (~100:1 möglich)
|
||||
- Hardware-Support in jedem Gerät seit ~2010
|
||||
- Hardware-Decoder in jedem Gerät seit ~2010
|
||||
- YouTube, Netflix, Blu-ray – alles H.264
|
||||
|
||||
**Features:**
|
||||
- Variable Block-Größen (16×16 bis 4×4)
|
||||
- Deblocking-Filter (reduziert Block-Artefakte)
|
||||
- Deblocking-Filter (reduziert Artefakte)
|
||||
|
||||
<!--
|
||||
H.264 revolutionierte Video-Streaming.
|
||||
Ohne H.264 kein Netflix, kein YouTube in HD.
|
||||
|
||||
Hardware-Decoder bedeutet: Kein CPU-Aufwand, kein Akku-Drain.
|
||||
Selbst billige Smartphones können H.264 abspielen.
|
||||
KLAUSURRELEVANT:
|
||||
- H.264 revolutionierte Video-Streaming
|
||||
- Ohne H.264 kein Netflix, kein YouTube HD
|
||||
- Hardware-Decoder = kein CPU-Aufwand, kein Akku-Drain
|
||||
- Selbst billigste Smartphones können H.264 abspielen
|
||||
-->
|
||||
|
||||
|
||||
@@ -486,17 +543,16 @@ Google, Netflix, Amazon, Microsoft, Apple, Mozilla...
|
||||
- 8K, HDR, hohe Frame-Rates
|
||||
|
||||
**Stand 2025:**
|
||||
YouTube und Netflix nutzen AV1 für 4K/8K
|
||||
YouTube, Netflix nutzen AV1 für 4K/8K
|
||||
Hardware-Encoder in aktuellen GPUs
|
||||
|
||||
<!--
|
||||
AOM = Alliance for Open Media, gegründet 2015.
|
||||
Historisch: Konkurrierende Tech-Giganten vereint.
|
||||
|
||||
Das Ziel: Nie wieder Patent-Chaos wie bei H.265.
|
||||
|
||||
Problem: Encoding ist sehr langsam (10-100× vs. H.264).
|
||||
Hardware-Encoder lösen das zunehmend.
|
||||
KLAUSURRELEVANT:
|
||||
- AOM gegründet 2015 – historisch: Konkurrenten vereint
|
||||
- Ziel: Nie wieder Patent-Chaos wie bei H.265
|
||||
- Problem: Encoding sehr langsam (10–100× vs. H.264)
|
||||
- Hardware-Encoder lösen das zunehmend
|
||||
- AV1 gewann 2024 einen Emmy für technische Innovation
|
||||
-->
|
||||
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
---
|
||||
marp: true
|
||||
theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Grundlagen IT- und Internettechnik (223015c)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: Grundlagen IT- und Internettechnik
|
||||
---
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--color-foreground: #1a1a2e;
|
||||
--color-highlight: #d63384;
|
||||
--color-dimmed: #4a4a6a;
|
||||
}
|
||||
section.invert {
|
||||
--color-foreground: #fff;
|
||||
}
|
||||
section {
|
||||
font-size: 1.7rem;
|
||||
}
|
||||
h1 {
|
||||
color: #a02060;
|
||||
}
|
||||
section.invert h1 {
|
||||
color: #fff;
|
||||
}
|
||||
h2 {
|
||||
color: #1f2937;
|
||||
}
|
||||
pre {
|
||||
background: #0f0f23;
|
||||
color: #d63384;
|
||||
border-radius: 8px;
|
||||
border-left: 3px solid #d63384;
|
||||
}
|
||||
pre code {
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
}
|
||||
code {
|
||||
background: #1a1a2e;
|
||||
color: #d63384;
|
||||
padding: 0.15em 0.4em;
|
||||
border-radius: 4px;
|
||||
}
|
||||
a {
|
||||
color: var(--color-highlight);
|
||||
}
|
||||
section.klausur {
|
||||
background: repeating-linear-gradient(
|
||||
135deg,
|
||||
#fce4ec,
|
||||
#fce4ec 40px,
|
||||
#fff 40px,
|
||||
#fff 80px
|
||||
) !important;
|
||||
}
|
||||
@media print {
|
||||
section.klausur {
|
||||
background: #fce4ec !important;
|
||||
}
|
||||
}
|
||||
section.aufgabe {
|
||||
background: #fce4ec !important;
|
||||
}
|
||||
section.aufgabe footer {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- _class: invert -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _backgroundColor: #000 -->
|
||||
|
||||

|
||||
|
||||
# Grundlagen IT- und Internettechnik
|
||||
|
||||
**223015c** · Modul "Technik 1" · 1. Semester
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015c/](https://librete.ch/hdm/223015c/)
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
<!-- _class: lead -->
|
||||
|
||||
# Herzlich willkommen!
|
||||
## Einführung
|
||||
|
||||
---
|
||||
|
||||
# Über mich
|
||||
|
||||
**Michael Werner Czechowski**
|
||||
|
||||
- Systems and Platform Engineer
|
||||
- Schwerpunkte:
|
||||
- Web-Technologien, Barriere-Armut, Open Source
|
||||
- Hintergrund:
|
||||
- Philosophie (Uni Stuttgart)
|
||||
- Wirtschaftsinformatik (Leibniz-FH Hannover)
|
||||
- Kontakt: lb-czechowski@hdm-stuttgart.de
|
||||
|
||||
---
|
||||
|
||||
# Warum dieses Modul?
|
||||
|
||||
**Das Internet ist überall** – aber was steckt dahinter?
|
||||
|
||||
* Warum sehen Webseiten auf dem Handy anders aus?
|
||||
* Wie funktioniert eigentlich das Internet?
|
||||
* Wie erkennen Sie, ob eine Werbeagentur gute Arbeit leistet?
|
||||
* Was hat ein Unterseekabel mit meiner E-Mail zu tun?
|
||||
* **→ Die Technik dahinter verstehen und fundierte Entscheidungen treffen**
|
||||
|
||||
---
|
||||
|
||||
# Das Ziel
|
||||
|
||||
**Technische Grundlagen verstehen**, um fundierte Entscheidungen treffen zu können.
|
||||
|
||||
Als Digital- und MedienwirtschaftlerInnen werdet ihr täglich mit technischen Fragen konfrontiert:
|
||||
* Wie baue ich eine barrierearme Webseite?
|
||||
* Welches Protokoll für welchen Zweck?
|
||||
* Wie funktioniert das Web hinter den Kulissen?
|
||||
* **→ Mitreden können – und selbst Webseiten bauen!**
|
||||
|
||||
---
|
||||
|
||||
# Was Sie hier lernen werden
|
||||
|
||||
**In dieser Veranstaltung erwerben Sie folgende Kompetenzen:**
|
||||
|
||||
* Geschichte des Computers und Internets
|
||||
* HTML-Grundlagen und semantisches Markup
|
||||
* CSS für Layout und Gestaltung
|
||||
* Netzwerke und Protokolle (TCP/IP, DNS, HTTP(S))
|
||||
* "Barrierefreiheit" im Web
|
||||
* Grundlagen von JavaScript und Interaktivität
|
||||
|
||||
---
|
||||
|
||||
# Kurze Umfrage
|
||||
|
||||
**Bitte Hand heben:**
|
||||
* Wer hat schon mal eine Webseite gebaut?
|
||||
* Wer weiß, was HTML ist?
|
||||
* Wer hat schon mal CSS geschrieben?
|
||||
* Wer kennt den Unterschied zwischen Internet und WWW?
|
||||
* Wer hat schon mal mit JavaScript gearbeitet?
|
||||
|
||||
---
|
||||
|
||||
# Kursübersicht
|
||||
|
||||
**Kapitel:**
|
||||
|
||||
1. Geschichte, Grundlagen & **HTML**
|
||||
2. Netzwerke, Protokolle, **semantisches HTML** & **CSS**
|
||||
3. Interaktivität, Animationen & **JavaScript**
|
||||
|
||||
**Ziel:** "Gelernte Hilflosigkeit" ablegen
|
||||
|
||||
---
|
||||
|
||||
<!-- _class: klausur -->
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
<!-- _backgroundColor: #fce4ec -->
|
||||
|
||||
# Prüfungsleistung
|
||||
|
||||
**Nach aktuellem Kenntnisstand:**
|
||||
|
||||
* 90 min insg. (Technik 1)
|
||||
* Schriftliche Klausur (digital)
|
||||
* Teils offene Fragen
|
||||
* So gut wie kein Coding/Programmieren
|
||||
* **Prüfungsrelevant:** Folien sind markiert mit anderem Hintergrund
|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
<!-- _header: '' -->
|
||||
<!-- _footer: '' -->
|
||||
|
||||

|
||||
|
||||
@@ -4,7 +4,7 @@ theme: gaia
|
||||
paginate: true
|
||||
backgroundColor: #fff
|
||||
header: "Grundlagen IT- und Internettechnik (223015c)"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – WS 2025/26"
|
||||
footer: "Michael Czechowski – HdM Stuttgart – SoSe 2026"
|
||||
title: "Kapitel 3: Interaktivität & JavaScript"
|
||||
---
|
||||
|
||||
@@ -83,7 +83,7 @@ section.aufgabe footer {
|
||||
Digital- und Medienwirtschaft
|
||||
Hochschule der Medien Stuttgart
|
||||
|
||||
**Wintersemester 2025/26**
|
||||
**Sommersemester 2026**
|
||||
|
||||
[https://librete.ch/hdm/223015c/](https://librete.ch/hdm/223015c/)
|
||||
|
||||
@@ -208,6 +208,8 @@ Fehler werden hier auch angezeigt
|
||||
|
||||
# Variablen: Daten speichern
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
// Modern (empfohlen)
|
||||
let age = 25; // Kann geändert werden
|
||||
@@ -260,6 +262,8 @@ Template Literals mit Backticks!
|
||||
|
||||
# Arrays: Listen
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const colors = ["red", "green", "blue"];
|
||||
|
||||
@@ -284,6 +288,8 @@ Arrays sind veränderbar auch bei const
|
||||
|
||||
# Objects: Strukturierte Daten
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const person = {
|
||||
firstName: "Max",
|
||||
@@ -342,7 +348,7 @@ true || false // true (ODER)
|
||||
|
||||
**In der Browser-Konsole:**
|
||||
|
||||
1. Erstelle Variablen für dich:
|
||||
1. Erstellen Sie Variablen für sich:
|
||||
```javascript
|
||||
const name = "Your Name";
|
||||
let age = 20;
|
||||
@@ -413,6 +419,8 @@ Code-Block in geschweiften Klammern
|
||||
|
||||
# Schleifen: Wiederholen
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
// for-Schleife
|
||||
for (let i = 0; i < 5; i++) {
|
||||
@@ -491,15 +499,7 @@ Funktionale Programmierung, Original-Array bleibt unverändert
|
||||
- JavaScript kann diesen Baum **lesen und ändern**
|
||||
- Jedes HTML-Element = ein "Node"
|
||||
|
||||
```
|
||||
document
|
||||
└── html
|
||||
├── head
|
||||
│ └── title
|
||||
└── body
|
||||
├── h1
|
||||
└── p
|
||||
```
|
||||

|
||||
|
||||
<!--
|
||||
DOM = Programmierschnittstelle für HTML
|
||||
@@ -536,6 +536,8 @@ querySelectorAll = alle Treffer
|
||||
|
||||
# Elemente manipulieren
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const element = document.querySelector("#meinElement");
|
||||
|
||||
@@ -564,6 +566,8 @@ style = Inline-Styles (camelCase!)
|
||||
|
||||
# Klassen manipulieren
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const element = document.querySelector(".box");
|
||||
|
||||
@@ -592,6 +596,8 @@ toggle schaltet hin und her
|
||||
|
||||
# Elemente erstellen
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
// Neues Element erstellen
|
||||
const neuerAbsatz = document.createElement("p");
|
||||
@@ -660,6 +666,8 @@ Interaktive Webseiten durch Events
|
||||
|
||||
# Event Listener
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const button = document.querySelector("#meinButton");
|
||||
|
||||
@@ -737,6 +745,8 @@ target = auslösendes Element
|
||||
|
||||
# Event.preventDefault()
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
// Link ohne Navigation
|
||||
const link = document.querySelector("a");
|
||||
@@ -763,6 +773,8 @@ Formular-Validierung ohne Reload
|
||||
|
||||
# Beispiel: Toggle Dark Mode
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const toggleButton = document.querySelector("#darkModeToggle");
|
||||
const body = document.body;
|
||||
@@ -851,6 +863,8 @@ HTML (Struktur) + CSS (Design) + JavaScript (Interaktivität)
|
||||
|
||||
# Beispiel: Todo-Liste
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
const form = document.querySelector("#todoForm");
|
||||
const input = document.querySelector("#todoInput");
|
||||
@@ -893,6 +907,8 @@ Node.js für Backend
|
||||
|
||||
# Fetch: Daten laden
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
// Mit async/await (modern)
|
||||
async function loadData() {
|
||||
@@ -914,6 +930,8 @@ APIs = Schnittstellen zu Daten, JSON = JavaScript Object Notation
|
||||
|
||||
# LocalStorage: Daten speichern
|
||||
|
||||

|
||||
|
||||
```javascript
|
||||
// Speichern
|
||||
localStorage.setItem("name", "Max");
|
||||
|
||||
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 315 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: __TITLE__</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">__URL__</span>
|
||||
</div>
|
||||
<iframe src="__SRC__"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: a11y-error</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/email-form.html</span>
|
||||
</div>
|
||||
<iframe src="./a11y-error.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Fehlermeldung</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; padding: 1.2rem; }
|
||||
label { display: block; margin-bottom: 4px; font-weight: 600; }
|
||||
input {
|
||||
font: inherit;
|
||||
padding: 6px 10px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 2px solid #d63384;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#email-error {
|
||||
color: #d63384;
|
||||
font-size: 0.9em;
|
||||
margin-top: 6px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<label for="email">E-Mail-Adresse</label>
|
||||
<input id="email" type="email" aria-describedby="email-error" value="michael@">
|
||||
<p id="email-error" role="alert">
|
||||
Bitte geben Sie eine gültige E-Mail-Adresse ein.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 37 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: a11y-focus</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/focus.html</span>
|
||||
</div>
|
||||
<iframe src="./a11y-focus.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Fokus-Indikator</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; padding: 1.2rem; }
|
||||
:focus, .is-focused {
|
||||
outline: 2px solid blue;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
button:focus-visible, button.is-focused {
|
||||
box-shadow: 0 0 0 3px rgba(0, 100, 255, 0.5);
|
||||
}
|
||||
button { font: inherit; padding: 6px 14px; margin: 6px 0; display: block; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Tab-Taste drücken:</p>
|
||||
<button class="is-focused">Erster Button</button>
|
||||
<button>Zweiter Button</button>
|
||||
<button>Dritter Button</button>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: a11y-semantic</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/klick.html</span>
|
||||
</div>
|
||||
<iframe src="./a11y-semantic.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>div vs button</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; padding: 1.2rem; }
|
||||
h3 { margin: 0.8rem 0 0.4rem; font-size: 1rem; }
|
||||
.bad { color: #b91c1c; }
|
||||
.good { color: #15803d; }
|
||||
.button {
|
||||
display: inline-block;
|
||||
background: #e5e7eb;
|
||||
border: 1px solid #9ca3af;
|
||||
padding: 6px 14px;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
}
|
||||
button { font: inherit; padding: 6px 14px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3 class="bad">Schlecht (div)</h3>
|
||||
<div class="button" onclick="alert('!')">Klick mich</div>
|
||||
<p><small>❌ Tab überspringt, kein Enter, kein Screenreader</small></p>
|
||||
|
||||
<h3 class="good">Gut (button)</h3>
|
||||
<button type="button">Klick mich</button>
|
||||
<p><small>✅ Tastatur + Screenreader eingebaut</small></p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 49 KiB |
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ARP</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; background: #fff; font-family: system-ui, sans-serif; }
|
||||
body { padding: 30px; display: inline-block; }
|
||||
.row { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; }
|
||||
.actor {
|
||||
background: #1a1a2e;
|
||||
color: #fff;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
font-weight: 700;
|
||||
min-width: 160px;
|
||||
text-align: center;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.laptop { background: #1e40af; }
|
||||
.router { background: #c2410c; }
|
||||
.arrow-right, .arrow-left {
|
||||
width: 0; height: 0;
|
||||
border-top: 10px solid transparent;
|
||||
border-bottom: 10px solid transparent;
|
||||
}
|
||||
.arrow-right { border-left: 14px solid #d63384; }
|
||||
.arrow-left { border-right: 14px solid #15803d; }
|
||||
.bubble {
|
||||
padding: 10px 14px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.95rem;
|
||||
max-width: 460px;
|
||||
}
|
||||
.ask { background: #fce7f3; border: 2px solid #d63384; color: #7c2d12; }
|
||||
.reply { background: #dcfce7; border: 2px solid #15803d; color: #14532d; }
|
||||
.meta {
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
opacity: 0.7;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="row">
|
||||
<div class="actor laptop">Laptop</div>
|
||||
<div class="arrow-right"></div>
|
||||
<div class="bubble ask">
|
||||
<div class="meta">Broadcast</div>
|
||||
"Wer hat die IP 192.168.1.1? Sag mir deine MAC!"
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="bubble reply">
|
||||
<div class="meta">Antwort</div>
|
||||
"Das bin ich! Meine MAC ist 11:22:33:44:55:66"
|
||||
</div>
|
||||
<div class="arrow-left"></div>
|
||||
<div class="actor router">Router</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 41 KiB |
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Box-Modell Diagramm</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; background: #fff; font-family: system-ui, sans-serif; }
|
||||
body { padding: 40px; display: inline-block; box-sizing: border-box; }
|
||||
.layer {
|
||||
padding-top: 38px;
|
||||
padding-bottom: 30px;
|
||||
padding-left: 30px;
|
||||
padding-right: 30px;
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.layer::before {
|
||||
position: absolute;
|
||||
top: 8px; left: 14px;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
.margin { background: #fde68a; }
|
||||
.margin::before { content: "margin"; color: #92400e; }
|
||||
.border { background: #fca5a5; }
|
||||
.border::before { content: "border"; color: #991b1b; }
|
||||
.padding { background: #86efac; }
|
||||
.padding::before { content: "padding"; color: #166534; }
|
||||
.content {
|
||||
background: #93c5fd;
|
||||
width: 260px;
|
||||
height: 110px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #1e3a8a;
|
||||
font-weight: 700;
|
||||
font-size: 1.2rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="layer margin">
|
||||
<div class="layer border">
|
||||
<div class="layer padding">
|
||||
<div class="content">content</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: button</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/button.html</span>
|
||||
</div>
|
||||
<iframe src="./button.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Button</title>
|
||||
</head>
|
||||
<body>
|
||||
<button>Add to favorites</button>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Client/Server Ports</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; background: #fff; font-family: system-ui, sans-serif; }
|
||||
body { padding: 30px; display: inline-block; }
|
||||
.endpoint {
|
||||
border: 2px solid #4a4a6a;
|
||||
border-radius: 6px;
|
||||
padding: 18px 24px;
|
||||
margin-bottom: 24px;
|
||||
min-width: 380px;
|
||||
background: #f3f4f6;
|
||||
}
|
||||
.endpoint.client { background: #dbeafe; border-color: #1e40af; }
|
||||
.endpoint.server { background: #fed7aa; border-color: #c2410c; }
|
||||
.role {
|
||||
font-weight: 700;
|
||||
font-size: 1rem;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.client .role { color: #1e3a8a; }
|
||||
.server .role { color: #7c2d12; }
|
||||
.addr {
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 1.4rem;
|
||||
color: #0f172a;
|
||||
}
|
||||
.port {
|
||||
background: #fde68a;
|
||||
color: #7c2d12;
|
||||
padding: 1px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: 700;
|
||||
}
|
||||
.label {
|
||||
margin-top: 6px;
|
||||
font-size: 0.85rem;
|
||||
color: #4a4a6a;
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="endpoint client">
|
||||
<div class="role">Client</div>
|
||||
<div class="addr">141.62.xxx.xxx:<span class="port">52431</span></div>
|
||||
<div class="label">↳ zufälliger Port vom OS</div>
|
||||
</div>
|
||||
<div class="endpoint server">
|
||||
<div class="role">Server</div>
|
||||
<div class="addr">212.132.79.37:<span class="port">443</span></div>
|
||||
<div class="label">↳ HTTPS-Standardport</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 40 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: Kontrast</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/contrast.html</span>
|
||||
</div>
|
||||
<iframe src="./contrast-levels.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,97 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kontrast-Stufen</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; padding: 1.6rem; margin: 0; }
|
||||
.row {
|
||||
background: #fff;
|
||||
padding: 22px 20px;
|
||||
margin-bottom: 14px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
}
|
||||
.sample {
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
flex: 1;
|
||||
}
|
||||
.meta {
|
||||
text-align: right;
|
||||
font-size: 0.85rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ratio {
|
||||
font-family: ui-monospace, monospace;
|
||||
font-weight: 700;
|
||||
font-size: 0.95rem;
|
||||
color: #1a1a2e;
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.7rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
.fail { background: #fee2e2; color: #991b1b; }
|
||||
.aa-large { background: #fed7aa; color: #7c2d12; }
|
||||
.aa { background: #dcfce7; color: #166534; }
|
||||
.aaa { background: #bbf7d0; color: #14532d; }
|
||||
.hint {
|
||||
margin-top: 14px;
|
||||
font-size: 0.78rem;
|
||||
color: #6b7280;
|
||||
font-style: italic;
|
||||
text-align: right;
|
||||
}
|
||||
.hint a { color: #d63384; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="row" style="background: #fff;">
|
||||
<div class="sample" style="color: #aaaaaa;">Barrierefrei lesen</div>
|
||||
<div class="meta">
|
||||
<div class="ratio">2.3:1</div>
|
||||
<span class="badge fail">✗ Fail</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="background: #fff;">
|
||||
<div class="sample" style="color: #949494;">Barrierefrei lesen</div>
|
||||
<div class="meta">
|
||||
<div class="ratio">3:1</div>
|
||||
<span class="badge aa-large">AA Large</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="background: #fff;">
|
||||
<div class="sample" style="color: #767676;">Barrierefrei lesen</div>
|
||||
<div class="meta">
|
||||
<div class="ratio">4.5:1</div>
|
||||
<span class="badge aa">✓ AA</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="background: #fff;">
|
||||
<div class="sample" style="color: #595959;">Barrierefrei lesen</div>
|
||||
<div class="meta">
|
||||
<div class="ratio">7:1</div>
|
||||
<span class="badge aaa">✓ AAA</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="background: #fff;">
|
||||
<div class="sample" style="color: #1a1a1a;">Barrierefrei lesen</div>
|
||||
<div class="meta">
|
||||
<div class="ratio">16:1</div>
|
||||
<span class="badge aaa">✓ AAA+</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hint">Check: webaim.org/resources/contrastchecker</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 76 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-anatomie</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/anatomie.html</span>
|
||||
</div>
|
||||
<iframe src="./css-anatomie.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>CSS Anatomie</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; }
|
||||
p { color: blue; font-size: 16px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Dieser Absatz ist blau und 16 Pixel groß.</p>
|
||||
<p>Alle p-Elemente werden gleich gestylt.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 34 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-box-model</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/box-model.html</span>
|
||||
</div>
|
||||
<iframe src="./css-box-model.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Box-Modell</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; background: #fff; }
|
||||
.box { display: inline-block; }
|
||||
.layer {
|
||||
padding-top: 22px;
|
||||
padding-bottom: 18px;
|
||||
padding-left: 18px;
|
||||
padding-right: 18px;
|
||||
position: relative;
|
||||
}
|
||||
.layer::before {
|
||||
position: absolute;
|
||||
top: 4px; left: 8px;
|
||||
font-size: 0.75em;
|
||||
font-weight: 600;
|
||||
}
|
||||
.margin { background: #fde68a; }
|
||||
.margin::before { content: "margin"; color: #92400e; }
|
||||
.border { background: #fca5a5; }
|
||||
.border::before { content: "border"; color: #991b1b; }
|
||||
.padding { background: #86efac; }
|
||||
.padding::before { content: "padding"; color: #166534; }
|
||||
.content {
|
||||
background: #93c5fd;
|
||||
width: 140px;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #1e3a8a;
|
||||
font-weight: 600;
|
||||
}
|
||||
pre { background: #f3f4f6; padding: 10px; border-radius: 4px; font-size: 0.85em; margin-top: 1rem; font-family: ui-monospace, monospace; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div class="layer margin">
|
||||
<div class="layer border">
|
||||
<div class="layer padding">
|
||||
<div class="content">content</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<pre>.box {
|
||||
width: 140px;
|
||||
padding: 18px;
|
||||
border: 18px solid;
|
||||
margin: 18px;
|
||||
}</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-colors</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/colors.html</span>
|
||||
</div>
|
||||
<iframe src="./css-colors.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Farben</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; font-size: 14px; }
|
||||
.swatch { display: flex; align-items: center; margin-bottom: 8px; }
|
||||
.chip { width: 40px; height: 40px; border-radius: 4px; margin-right: 12px; border: 1px solid #e5e7eb; }
|
||||
code { background: #f3f4f6; padding: 2px 6px; border-radius: 3px; font-family: ui-monospace, monospace; font-size: 0.85em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="swatch"><div class="chip" style="background: red;"></div><code>color: red;</code></div>
|
||||
<div class="swatch"><div class="chip" style="background: rebeccapurple;"></div><code>color: rebeccapurple;</code></div>
|
||||
<div class="swatch"><div class="chip" style="background: #FF0000;"></div><code>#FF0000</code></div>
|
||||
<div class="swatch"><div class="chip" style="background: rgb(255, 0, 0);"></div><code>rgb(255, 0, 0)</code></div>
|
||||
<div class="swatch"><div class="chip" style="background: rgba(255, 0, 0, 0.5);"></div><code>rgba(255, 0, 0, 0.5)</code></div>
|
||||
<div class="swatch"><div class="chip" style="background: hsl(0, 100%, 50%);"></div><code>hsl(0, 100%, 50%)</code></div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 46 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-combinators</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/combinators.html</span>
|
||||
</div>
|
||||
<iframe src="./css-combinators.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Kombinatoren</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; font-size: 14px; }
|
||||
article p { line-height: 1.6; background: #fef3c7; padding: 4px; }
|
||||
nav > a { text-decoration: none; color: #d63384; margin-right: 10px; font-weight: 600; }
|
||||
h2 + p { font-size: 1.2em; color: #065f46; }
|
||||
p.wichtig { color: red; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="#">Link</a><a href="#">Link</a>
|
||||
</nav>
|
||||
<article>
|
||||
<h2>Artikel-Überschrift</h2>
|
||||
<p>Direkt nach h2 (größer, grün).</p>
|
||||
<p>Normaler Absatz im article (gelb).</p>
|
||||
<p class="wichtig">Wichtig (rot).</p>
|
||||
</article>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 47 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-pseudo-classes</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/pseudo-classes.html</span>
|
||||
</div>
|
||||
<iframe src="./css-pseudo-classes.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Pseudo-Klassen</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; font-size: 14px; }
|
||||
a { color: #2563eb; }
|
||||
a:hover, a.is-hovered { color: red; text-decoration: underline; }
|
||||
a:visited, a.is-visited { color: purple; }
|
||||
input:focus, input.is-focused { border-color: blue; outline: 2px solid blue; }
|
||||
input { padding: 4px 8px; border: 1px solid #9ca3af; border-radius: 3px; }
|
||||
ul { list-style: none; padding: 0; }
|
||||
li { padding: 6px 10px; }
|
||||
li:first-child, li.is-first { font-weight: bold; }
|
||||
li:nth-child(odd), li.is-odd { background: #eee; }
|
||||
h3 { margin: 0.6rem 0 0.3rem; font-size: 0.95rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>:hover / :visited</h3>
|
||||
<a href="#" class="is-hovered">Link mit Hover</a> ·
|
||||
<a href="#" class="is-visited">Besuchter Link</a>
|
||||
|
||||
<h3>:focus</h3>
|
||||
<input class="is-focused" value="fokussiert">
|
||||
|
||||
<h3>:first-child, :nth-child(odd)</h3>
|
||||
<ul>
|
||||
<li class="is-first is-odd">Erster (bold, zebra)</li>
|
||||
<li>Zweiter</li>
|
||||
<li class="is-odd">Dritter (zebra)</li>
|
||||
<li>Vierter</li>
|
||||
<li class="is-odd">Fünfter (zebra)</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 57 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-pseudo-elements</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/pseudo-elements.html</span>
|
||||
</div>
|
||||
<iframe src="./css-pseudo-elements.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Pseudo-Elemente</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; font-size: 14px; }
|
||||
.required::before {
|
||||
content: "* ";
|
||||
color: red;
|
||||
}
|
||||
p.drop { line-height: 1.5; }
|
||||
p.drop::first-letter {
|
||||
font-size: 3em;
|
||||
font-weight: bold;
|
||||
color: #d63384;
|
||||
float: left;
|
||||
line-height: 0.9;
|
||||
padding-right: 6px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
label { display: block; margin-top: 10px; }
|
||||
input { padding: 4px 8px; border: 1px solid #9ca3af; border-radius: 3px; margin-top: 3px; }
|
||||
h3 { margin: 0.6rem 0 0.3rem; font-size: 0.95rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h3>::before (Pflichtfeld-Sternchen)</h3>
|
||||
<label class="required">E-Mail-Adresse</label>
|
||||
<input type="email">
|
||||
|
||||
<h3>::first-letter (Initial-Buchstabe)</h3>
|
||||
<p class="drop">Lorem ipsum dolor sit amet. Der erste Buchstabe wird per CSS hervorgehoben – kein extra HTML nötig.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Responsive Container</title>
|
||||
<style>
|
||||
body { padding: 0; margin: 0; font-family: system-ui, sans-serif; background: #fff; }
|
||||
.container {
|
||||
padding: 1rem;
|
||||
background: white;
|
||||
color: #111;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
border: 1px solid #d1d5db;
|
||||
}
|
||||
.container::before { content: "< 768px — weiß, padding 1rem"; }
|
||||
@media (min-width: 768px) {
|
||||
.container { padding: 2rem; background: red; color: white; border: none; }
|
||||
.container::before { content: "≥ 768px — rot, padding 2rem"; }
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.container { background: green; }
|
||||
.container::before { content: "≥ 1024px — grün"; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-responsive</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/responsive.html</span>
|
||||
</div>
|
||||
<iframe src="./css-responsive.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,45 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Responsive Design – 3 Viewports</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; font-family: system-ui, sans-serif; background: #fff; }
|
||||
body { padding: 1rem; }
|
||||
.viewport {
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid #9ca3af;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.bar {
|
||||
background: #e5e7eb;
|
||||
padding: 4px 10px;
|
||||
font-size: 11px;
|
||||
color: #374151;
|
||||
font-family: ui-monospace, monospace;
|
||||
border-bottom: 1px solid #9ca3af;
|
||||
}
|
||||
iframe { display: block; width: 100%; border: 0; }
|
||||
.vp-mobile iframe { width: 360px; }
|
||||
.vp-tablet iframe { width: 800px; }
|
||||
.vp-desktop iframe { width: 1100px; }
|
||||
.vp-mobile { width: 362px; }
|
||||
.scroll { overflow: hidden; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="viewport vp-mobile">
|
||||
<div class="bar">Mobile @ 360px</div>
|
||||
<div class="scroll"><iframe src="./css-responsive-container.html" height="80"></iframe></div>
|
||||
</div>
|
||||
<div class="viewport vp-tablet">
|
||||
<div class="bar">Tablet @ 800px</div>
|
||||
<div class="scroll" style="overflow-x: auto;"><iframe src="./css-responsive-container.html" height="100"></iframe></div>
|
||||
</div>
|
||||
<div class="viewport vp-desktop">
|
||||
<div class="bar">Desktop @ 1100px</div>
|
||||
<div class="scroll" style="overflow-x: auto;"><iframe src="./css-responsive-container.html" height="100"></iframe></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 51 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-selector-class</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/selector-class.html</span>
|
||||
</div>
|
||||
<iframe src="./css-selector-class.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Klassen-Selektor</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; }
|
||||
.wichtig { color: red; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="wichtig">Dieser Text ist wichtig.</p>
|
||||
<p>Dieser nicht.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-selector-element</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/selector-element.html</span>
|
||||
</div>
|
||||
<iframe src="./css-selector-element.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Element-Selektor</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; }
|
||||
p { color: gray; font-family: Georgia, serif; }
|
||||
h1, h2, h3 { font-family: sans-serif; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Überschrift (sans-serif)</h1>
|
||||
<p>Absatz: grau, Georgia (serif).</p>
|
||||
<h2>Untertitel (sans-serif)</h2>
|
||||
<p>Noch ein grauer Absatz.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 48 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-selector-id</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/selector-id.html</span>
|
||||
</div>
|
||||
<iframe src="./css-selector-id.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>ID-Selektor</title>
|
||||
<style>
|
||||
body { padding: 0; margin: 0; font-family: system-ui, sans-serif; }
|
||||
#hauptnavigation {
|
||||
background: #333;
|
||||
padding: 1rem;
|
||||
color: white;
|
||||
}
|
||||
#hauptnavigation a { color: #fff; margin-right: 1rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="hauptnavigation">
|
||||
<a href="#">Home</a>
|
||||
<a href="#">Kurse</a>
|
||||
<a href="#">Kontakt</a>
|
||||
</nav>
|
||||
<p style="padding: 1rem;">Rest der Seite.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Preview: css-specificity</title>
|
||||
<style>
|
||||
:root {
|
||||
--hl: #d63384;
|
||||
--dark: #0f0f23;
|
||||
--chrome: #1a1a2e;
|
||||
--muted: #4a4a6a;
|
||||
}
|
||||
html, body { margin: 0; padding: 0; background: var(--dark); font-family: system-ui, -apple-system, sans-serif; }
|
||||
.browser { box-sizing: border-box; width: 100vw; min-height: 100vh; padding: 18px; }
|
||||
.window { background: #fff; border-radius: 10px; box-shadow: 0 12px 32px rgba(0,0,0,.35); overflow: hidden; border: 2px solid var(--hl); }
|
||||
.chrome { background: var(--chrome); border-bottom: 2px solid var(--hl); padding: 10px 14px; display: flex; align-items: center; gap: 7px; }
|
||||
.dot { width: 11px; height: 11px; border-radius: 50%; opacity: 0.9; }
|
||||
.r { background: #ff5f56; } .y { background: #ffbd2e; } .g { background: #27c93f; }
|
||||
.url { flex: 1; margin-left: 12px; background: var(--dark); border: 1px solid var(--hl); border-radius: 6px; padding: 5px 10px; font: 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: var(--hl); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
iframe { display: block; width: 100%; height: 700px; border: 0; background: #fff; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="browser">
|
||||
<div class="window">
|
||||
<div class="chrome">
|
||||
<span class="dot r"></span><span class="dot y"></span><span class="dot g"></span>
|
||||
<span class="url">file:///beispiel/specificity.html</span>
|
||||
</div>
|
||||
<iframe src="./css-specificity.html"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Spezifität</title>
|
||||
<style>
|
||||
body { padding: 1.2rem; font-family: system-ui, sans-serif; }
|
||||
p { color: blue; } /* 0,0,0,1 */
|
||||
.text { color: green; } /* 0,0,1,0 */
|
||||
#intro { color: red; } /* 0,1,0,0 */
|
||||
code { background: #f3f4f6; padding: 1px 5px; border-radius: 3px; font-size: 0.9em; }
|
||||
.row { margin-bottom: 10px; }
|
||||
.label { color: #6b7280; font-size: 0.85em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="row">
|
||||
<p>Nur <code>p</code>: <strong>blau</strong></p>
|
||||
<span class="label">0,0,0,1</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p class="text">Nur <code>.text</code>: <strong>grün</strong> schlägt p</p>
|
||||
<span class="label">0,0,1,0 > 0,0,0,1</span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p id="intro" class="text">ID <code>#intro</code>: <strong>rot</strong> schlägt alles</p>
|
||||
<span class="label">0,1,0,0 > 0,0,1,0</span>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Decapsulation Stack</title>
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; background: #fff; font-family: system-ui, sans-serif; }
|
||||
body { padding: 30px; display: inline-block; }
|
||||
.stack { display: flex; flex-direction: column; gap: 0; }
|
||||
.layer {
|
||||
border: 2px solid;
|
||||
border-radius: 6px;
|
||||
padding: 10px 18px;
|
||||
min-width: 540px;
|
||||
font-size: 0.95rem;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.layer-name { font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; opacity: 0.8; }
|
||||
.layer-desc { font-family: ui-monospace, monospace; margin-top: 3px; }
|
||||
.check { margin-top: 3px; font-size: 0.85rem; font-style: italic; }
|
||||
.http { background: #e0e7ff; border-color: #4f46e5; color: #3730a3; }
|
||||
.tcp { background: #dbeafe; border-color: #1e40af; color: #1e3a8a; }
|
||||
.ip { background: #dcfce7; border-color: #15803d; color: #14532d; }
|
||||
.eth { background: #fed7aa; border-color: #c2410c; color: #7c2d12; }
|
||||
.bit { background: #e5e7eb; border-color: #4b5563; color: #1f2937; }
|
||||
.arrow {
|
||||
align-self: center;
|
||||
width: 0; height: 0;
|
||||
border-left: 9px solid transparent;
|
||||
border-right: 9px solid transparent;
|
||||
border-top: 12px solid #d63384;
|
||||
margin: 2px 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="stack">
|
||||
<div class="layer bit">
|
||||
<div class="layer-name">Physical</div>
|
||||
<div class="layer-desc">Bits empfangen</div>
|
||||
</div>
|
||||
<div class="arrow"></div>
|
||||
<div class="layer eth">
|
||||
<div class="layer-name">Ethernet-Frame</div>
|
||||
<div class="check">MAC = meine MAC? ✓ auspacken</div>
|
||||
</div>
|
||||
<div class="arrow"></div>
|
||||
<div class="layer ip">
|
||||
<div class="layer-name">IP-Paket</div>
|
||||
<div class="check">Ziel-IP = meine IP? ✓ auspacken</div>
|
||||
</div>
|
||||
<div class="arrow"></div>
|
||||
<div class="layer tcp">
|
||||
<div class="layer-name">TCP-Segment</div>
|
||||
<div class="check">Port 52431 = mein Browser? ✓ auspacken</div>
|
||||
</div>
|
||||
<div class="arrow"></div>
|
||||
<div class="layer http">
|
||||
<div class="layer-name">HTTP-Response</div>
|
||||
<div class="layer-desc">"HTTP/1.1 200 OK ..."</div>
|
||||
<div class="check">→ Browser rendert Seite</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 67 KiB |