Redesign TinyTorch CLI logo with vertical 'tiny' integration

- Create bold ASCII art logo with 'tiny' spelled vertically
- Add flame banner above TORCH for visual impact
- Update tagline to 'Don't import the future. Build it from tensors up.'
- Simplify logo command to show philosophy and meaning
- Remove unused preferences system
- Clean up display logic and improve color scheme

The new design features 'tiny' integrated vertically alongside TORCH,
creating a unique visual identity that reinforces the framework's philosophy
of building from small foundations up to powerful systems.
This commit is contained in:
Vijay Janapa Reddi
2025-09-20 19:39:30 -04:00
parent f5d8092793
commit 6bee718ac6
4 changed files with 167 additions and 320 deletions

View File

@@ -1,5 +1,5 @@
"""
Logo command for TinyTorch CLI: displays beautiful ASCII art logo.
Logo command for TinyTorch CLI: explains the symbolism and meaning behind TinyTorch.
"""
from argparse import ArgumentParser, Namespace
@@ -7,11 +7,9 @@ from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from rich.align import Align
from rich.columns import Columns
import time
from pathlib import Path
from .base import BaseCommand
from ..core.preferences import UserPreferences
class LogoCommand(BaseCommand):
@property
@@ -20,228 +18,103 @@ class LogoCommand(BaseCommand):
@property
def description(self) -> str:
return "Display the TinyTorch ASCII art logo with theme support"
return "Learn about the TinyTorch logo and its meaning"
def add_arguments(self, parser: ArgumentParser) -> None:
parser.add_argument("--animate", action="store_true", help="Show animated flame effect")
parser.add_argument("--simple", action="store_true", help="Show simple logo without extra elements")
parser.add_argument("--bright", action="store_true", help="Use bright/vivid theme with yellow center")
parser.add_argument("--theme", choices=["standard", "bright"], help="Choose logo theme")
parser.add_argument("--save-theme", action="store_true", help="Save the selected theme as default")
parser.add_argument("--image", action="store_true",
help="Show path to the actual logo image file")
def run(self, args: Namespace) -> int:
# Determine theme
theme = self._get_theme(args)
# Save theme preference if requested
if args.save_theme:
self._save_theme_preference(theme)
self.console.print(f"[green]✅ Saved '{theme}' as default theme[/green]")
if args.animate:
self.show_animated_logo(theme=theme)
elif args.simple:
self.show_simple_logo(theme=theme)
else:
self.show_full_logo(theme=theme)
return 0
def show_full_logo(self, theme: str = "standard"):
"""Show the complete logo with version and tagline."""
console = self.console
# ASCII Art Logo (now returns a Text object)
logo_art = self.get_logo_art(theme=theme)
# Display the ASCII logo first
from ..core.console import print_ascii_logo
print_ascii_logo()
# Add additional tagline
tagline = Text()
tagline.append("\nBuild Complete Neural Networks from First Principles", style="dim cyan")
# Create the explanation text
explanation = Text()
# Combine logo and tagline
full_content = Text()
full_content.append(logo_art)
full_content.append(tagline)
# Title
explanation.append("\n🔥 The TinyTorch Story\n\n", style="bold yellow")
# Display with rich styling
border_style = "bright_blue" if theme == "standard" else "bright_yellow"
console.print()
# The flame and sparks
explanation.append("The Flame 🔥\n", style="bold orange1")
explanation.append(
"The flame represents the spark of understanding - how learning ML systems "
"starts with a small flame that can grow into mastery. Just as a torch "
"lights the way in darkness, TinyTorch illuminates the path to understanding "
"neural networks from first principles.\n\n",
style="dim"
)
# The sparks
explanation.append("The Sparks ✨\n", style="bold orange1")
explanation.append(
"In our full logo, sparks fly from the flame - representing how knowledge "
"spreads. Each concept you learn sends off sparks that ignite understanding "
"in other areas. What starts small can catch fire and grow into something powerful.\n\n",
style="dim"
)
# The "tiny" philosophy
explanation.append("Why 'Tiny'? \n", style="bold cyan")
explanation.append(
"Inspired by TinyML's philosophy: small systems are accessible and powerful. "
"'Tiny' means we start with the fundamentals, building understanding piece by piece. "
"By keeping things small and focused, complex concepts become approachable. "
"Every giant neural network started with tiny building blocks - tensors, gradients, "
"and simple operations.\n\n",
style="dim"
)
# The "Torch" connection
explanation.append("Why 'Torch'? \n", style="bold cyan")
explanation.append(
"A tribute to PyTorch, the framework that revolutionized deep learning. "
"While PyTorch is powerful, its complexity can overwhelm beginners. "
"TinyTorch distills those same concepts into their essence, letting you "
"build and understand every component. You're not just using a framework - "
"you're building one.\n\n",
style="dim"
)
# The neural network in the flame
explanation.append("The Hidden Network 🔥\n", style="bold orange1")
explanation.append(
"Look closely at our logo - within the flame, there's a neural network pattern. "
"This represents the core truth: inside every ML system, no matter how complex, "
"are simple, connected components working together. The flame contains the network, "
"just as understanding contains mastery.\n\n",
style="dim"
)
# The philosophy
explanation.append("The Philosophy 💡\n", style="bold green")
explanation.append(
"TinyTorch embodies the belief that anyone can understand ML systems by building them. "
"Start small, understand deeply, build everything. What begins as a tiny flame of "
"curiosity becomes the torch that lights your path to ML engineering mastery.\n\n",
style="dim"
)
# Display in a nice panel
console.print(Panel(
Align.center(full_content),
border_style=border_style,
explanation,
title="[bold]About the TinyTorch Logo[/bold]",
border_style="orange1",
padding=(1, 2)
))
console.print()
# Show quick stats
self.show_progress_stats(theme=theme)
def show_simple_logo(self, theme: str = "standard"):
"""Show just the ASCII art logo."""
console = self.console
logo_art = self.get_logo_art(theme=theme) # Now returns a Text object
# Show logo file path if requested
if args.image:
logo_path = Path(__file__).parent.parent.parent / "logo" / "logo.png"
if logo_path.exists():
console.print(f"\n[cyan]Logo image location:[/cyan] {logo_path}")
console.print("[dim]Open this file to see the full logo with sparks[/dim]")
else:
console.print(f"\n[yellow]Logo image not found at expected location[/yellow]")
console.print()
console.print(Align.center(logo_art))
console.print()
def show_animated_logo(self, theme: str = "standard"):
"""Show logo with animated flame effect."""
console = self.console
# Final inspiring message
console.print("\n[bold yellow]🔥 Start small. Understand deeply. Build everything.[/bold yellow]\n")
# Animation frames - different for each theme
if theme == "bright":
flame_frames = ["", "", "🔥", "💫", ""] # More energetic
else:
flame_frames = ["🔥", "🔶", "🔸", "", "🔥"] # Professional
border_style = "bright_blue" if theme == "standard" else "bright_yellow"
for i in range(10): # Show 10 frames
console.clear()
# Get current flame
flame = flame_frames[i % len(flame_frames)]
# Create animated logo (now returns a Text object)
logo_art = self.get_logo_art(theme=theme, flame_char=flame)
tagline = Text()
tagline.append("\nBuild Complete Neural Networks from First Principles", style="dim cyan")
full_content = Text()
full_content.append(logo_art)
full_content.append(tagline)
console.print()
console.print(Panel(
Align.center(full_content),
border_style=border_style,
padding=(1, 2)
))
time.sleep(0.2)
# Show final static version
self.show_full_logo(theme=theme)
def get_logo_art(self, theme: str = "standard", flame_char: str = None):
"""Generate the ASCII art logo matching the actual TinyTorch design."""
# Set default flame character based on theme
if flame_char is None:
flame_char = "" if theme == "bright" else "🔥"
# Create a Text object to properly handle Rich markup
logo_text = Text()
# Theme-specific styling
if theme == "bright":
# Bright theme: vivid yellow center, orange "tiny" text
top_flames = "✨🔥✨"
else:
# Standard theme: professional orange/red tones
top_flames = f"{flame_char}{flame_char}"
# ASCII art representing the real TinyTorch logo:
# Flame on left with neural network inside, "tiny TORCH" on right
logo_lines = [
f" {top_flames} ",
" ╱──╲ ████████╗ ██████╗ ██████╗ ██████╗██╗ ██╗",
" ⚡ ╲ ╚══██╔══╝██╔═══██╗██╔══██╗██╔════╝██║ ██║",
" ╲ ╲ ██║ ██║ ██║██████╔╝██║ ███████║",
" │ ●━━━● │ ██║ ██║ ██║██╔══██╗██║ ██╔══██║",
" │ │ ⚡ │ │ ██║ ╚██████╔╝██║ ██║╚██████╗██║ ██║",
" │ ●━┬━● │ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝",
" ╲ ╲●╱ ",
" ╲━━━╱ ",
" ╲╱ "
]
# Add the first line with styled "tiny"
if theme == "bright":
logo_text.append(logo_lines[0])
logo_text.append("tiny", style="bold orange1")
logo_text.append(" \n")
else:
logo_text.append(logo_lines[0])
logo_text.append("tiny", style="dim")
logo_text.append(" \n")
# Add the main ASCII art lines
for line in logo_lines[1:8]:
logo_text.append(line + "\n")
# Add the tagline with proper styling
logo_text.append(logo_lines[8])
if theme == "bright":
logo_text.append(flame_char, style="bright_yellow")
logo_text.append(" Learn ML Systems by Building Them", style="bold orange1")
else:
logo_text.append(f"{flame_char} Learn ML Systems by Building Them", style="orange1")
logo_text.append("\n")
# Add the final line
logo_text.append(logo_lines[9])
return logo_text
def show_progress_stats(self, theme: str = "standard"):
"""Show current progress through the course."""
console = self.console
# Check how many modules are completed
# This is a simplified version - could be enhanced to check actual module status
# Theme-specific emoji and styling
if theme == "bright":
journey_emoji = "🌟"
fire_emoji = ""
start_emoji = "💫"
border_style = "bright_yellow"
else:
journey_emoji = "📊"
fire_emoji = "🔥"
start_emoji = "🚀"
border_style = "bright_green"
stats_table = f"""
[bold cyan]{journey_emoji} Your TinyTorch Journey[/bold cyan]
[bold green]Module Progress:[/bold green]
🎯 17 Total Modules Available
📚 Build from Tensors → Training → TinyGPT
{fire_emoji} Learn by Implementation, Not Theory
[bold yellow]Quick Commands:[/bold yellow]
[dim]tito module status[/dim] - Check module progress
[dim]tito checkpoint timeline[/dim] - Visual progress tracker
[dim]tito module view[/dim] - Start coding in Jupyter Lab
[dim]tito system doctor[/dim] - Diagnose any issues
[bold magenta]Ready to Build ML Systems? Start with:[/bold magenta]
[dim]tito module view 01_setup[/dim] - Configure your environment
"""
console.print(Panel(
Text.from_markup(stats_table),
title=f"{start_emoji} Getting Started",
border_style=border_style,
padding=(1, 2)
))
def _get_theme(self, args: Namespace) -> str:
"""Determine the theme to use based on arguments and preferences."""
# Check command line arguments first
if args.bright:
return "bright"
if args.theme:
return args.theme
# Fall back to saved preferences
prefs = UserPreferences.load_from_file()
return prefs.logo_theme
def _save_theme_preference(self, theme: str) -> None:
"""Save the theme preference to config file."""
prefs = UserPreferences.load_from_file()
prefs.logo_theme = theme
prefs.save_to_file()
return 0

View File

@@ -22,57 +22,96 @@ def get_console() -> Console:
_console = Console(stderr=False)
return _console
def print_banner():
"""Print the TinyTorch banner using Rich."""
def print_banner(compact: bool = False):
"""Print the TinyTorch banner using Rich with clean block text style."""
console = get_console()
banner_text = Text("Tiny🔥Torch: Build ML Systems from Scratch", style="bold red")
if compact:
print_compact_banner()
else:
# Create banner text that matches the clean block text theme
banner_text = Text()
banner_text.append("tiny", style="dim cyan")
banner_text.append("🔥", style="red")
banner_text.append("TORCH", style="bold orange1")
banner_text.append(": Build ML Systems from Scratch", style="dim")
console.print(Panel(banner_text, style="bright_blue", padding=(1, 2)))
def print_compact_banner():
"""Print a compact TinyTorch banner with 'tiny' above TORCH."""
console = get_console()
# Create compact banner text
banner_text = Text()
banner_text.append("tiny", style="dim cyan")
banner_text.append("\n🔥", style="red")
banner_text.append("TORCH", style="bold orange1")
banner_text.append(": Build ML Systems from Scratch", style="dim")
console.print(Panel(banner_text, style="bright_blue", padding=(1, 2)))
def print_ascii_logo():
"""Print the beautiful ASCII art TinyTorch logo matching the real design."""
def print_ascii_logo(compact: bool = False):
"""Print the clean, minimal ASCII art TinyTorch logo."""
console = get_console()
if compact:
print_compact_ascii_logo()
return
# Create styled logo text with proper Rich formatting
logo_text = Text()
# ASCII Art Logo lines
# ============================================
# TINYTORCH LOGO - EDIT HERE!
# ============================================
# To edit: Change the ASCII characters in logo_lines
# Add/remove spaces at the beginning of each line to adjust positioning
logo_lines = [
" 🔥🔥 ",
" ╱──╲ ",
" ● ╲ ████████╗ ██████╗ ██████╗ ██████╗██╗ ██╗",
" ╲ ╲═██╔══╝██╔═══██╗██╔══██╗██╔════╝██║ ██║",
" │ ●───● │ ██║ ██║ ██║██████╔╝██║ ███████║",
" │ │ ● │ │ ██║ ██║ ██║██╔══██╗██║ ██╔══██║",
" │ ●─┬─● │ ██║ ╚██████╔╝██║ ██║╚██████╗██║ ██║",
" ╲ ╲●╱ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝",
" ╲───╱ ",
" ╲─╱ "
# Flames above each TORCH letter
" 🔥🔥🔥🔥",
" ████████╗ ██████╗ ██████╗ ██████╗██╗ ██╗", # TORCH line 1
"t═██╔══╝██╔═══██╗██╔══██╗██╔════╝██║ ██║", # TORCH line 2
" i ██║ ██║ ██║██████╔╝██║ ███████║", # TORCH line 3
" n ██║ ██║ ██║██╔══██╗██║ ██╔══██║", # TORCH line 4
" y ██║ ╚██████╔╝██║ ██║╚██████╗██║ ██║", # TORCH line 5
" ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝" # TORCH line 6
]
# Add the first line
logo_text.append(logo_lines[0] + "\n")
# ============================================
# COLOR CONFIGURATION - EDIT COLORS HERE!
# ============================================
# Available colors: black, red, green, yellow, blue, magenta, cyan, white
# Prefix with 'bright_' for brighter versions (e.g., 'bright_red')
# Add 'bold' for bold text (e.g., 'bold red' or 'bold bright_black')
# Add the second line with styled "tiny"
logo_text.append(logo_lines[1])
logo_text.append("tiny", style="dim")
logo_text.append(" \n")
FLAME_COLOR = "yellow" # Color for 🔥 emoji
TINY_COLOR = "bold yellow" # Color for "tiny" text (warmer, more visible)
TORCH_COLOR = "bold white" # Color for "TORCH" text (better contrast)
TAGLINE_COLOR = "orange1" # Color for tagline
# Add the main ASCII art lines
for line in logo_lines[2:9]:
logo_text.append(line + "\n")
# Add the tagline with proper styling
logo_text.append(logo_lines[9])
logo_text.append("🔥 Learn ML Systems by Building Them", style="orange1")
# Process and apply colors to each line
for i, line in enumerate(logo_lines):
if i == 0: # Flame line
logo_text.append(line, style=FLAME_COLOR)
elif i == 4: # Line with tiny + TORCH
# Find where "tiny" ends and TORCH begins (look for ██)
if "██║" in line:
torch_start = line.find("██║")
tiny_part = line[:torch_start]
torch_part = line[torch_start:]
logo_text.append(tiny_part, style=TINY_COLOR)
logo_text.append(torch_part, style=TORCH_COLOR)
else:
logo_text.append(line, style=TORCH_COLOR)
else: # Pure TORCH lines
logo_text.append(line, style=TORCH_COLOR)
logo_text.append("\n")
# Add tagline
tagline = Text()
tagline.append("\nBuild Complete Neural Networks from First Principles", style="dim cyan")
logo_text.append("\n🔥 Don't import the future. Build it from tensors up.", style="orange1")
logo_text.append("\n")
# Combine logo and tagline
full_content = Text()
full_content.append(logo_text)
full_content.append(tagline)
# Display centered with rich styling
console.print()
@@ -83,6 +122,11 @@ def print_ascii_logo():
))
console.print()
def print_compact_ascii_logo():
"""Print the compact ASCII art TinyTorch logo - same as main logo now."""
# Just use the main logo since it's already compact and clean
print_ascii_logo(compact=False)
def print_error(message: str, title: str = "Error"):
"""Print an error message with consistent formatting."""
console = get_console()

View File

@@ -1,67 +0,0 @@
"""
User preferences management for TinyTorch CLI.
"""
import json
from pathlib import Path
from typing import Dict, Any, Optional
from dataclasses import dataclass, asdict
@dataclass
class UserPreferences:
"""User preferences for TinyTorch CLI."""
# Logo preferences
logo_theme: str = "standard" # "standard" or "bright"
# Future preferences can be added here
# animation_enabled: bool = True
# color_scheme: str = "auto"
@classmethod
def load_from_file(cls, config_file: Optional[Path] = None) -> 'UserPreferences':
"""Load preferences from config file."""
if config_file is None:
config_file = cls.get_default_config_path()
if not config_file.exists():
# Return defaults if no config file exists
return cls()
try:
with open(config_file, 'r') as f:
data = json.load(f)
# Create instance with loaded data, using defaults for missing keys
return cls(**{
key: data.get(key, getattr(cls(), key))
for key in cls.__dataclass_fields__
})
except (json.JSONDecodeError, FileNotFoundError, KeyError):
# Return defaults if config file is corrupted
return cls()
def save_to_file(self, config_file: Optional[Path] = None) -> None:
"""Save preferences to config file."""
if config_file is None:
config_file = self.get_default_config_path()
# Ensure config directory exists
config_file.parent.mkdir(parents=True, exist_ok=True)
with open(config_file, 'w') as f:
json.dump(asdict(self), f, indent=2)
@staticmethod
def get_default_config_path() -> Path:
"""Get the default config file path."""
# Look for project root first
current = Path.cwd()
while current != current.parent:
if (current / 'pyproject.toml').exists():
return current / '.tito' / 'config.json'
current = current.parent
# Fallback to current directory
return Path.cwd() / '.tito' / 'config.json'

View File

@@ -95,7 +95,6 @@ Convenience Commands:
book Build and manage Jupyter Book
grade Simplified grading interface (wraps NBGrader)
demo Run AI capability demos (show what your framework can do!)
logo Display the beautiful TinyTorch ASCII art logo
Examples:
tito system info Show system information
@@ -103,7 +102,6 @@ Examples:
tito module view 01_setup Start coding in Jupyter Lab
tito export 01_tensor Export specific module to package
tito checkpoint timeline Visual progress timeline
tito logo --animate Show animated ASCII logo
tito book build Build the Jupyter Book locally
"""
)
@@ -174,8 +172,8 @@ Examples:
if hasattr(parsed_args, 'no_color') and parsed_args.no_color:
self.config.no_color = True
# Show banner for interactive commands
if parsed_args.command and not self.config.no_color:
# Show banner for interactive commands (except logo which has its own display)
if parsed_args.command and not self.config.no_color and parsed_args.command != 'logo':
print_banner()
# Validate environment for most commands (skip for doctor)
@@ -206,13 +204,12 @@ Examples:
" [bold green]export[/bold green] - Export modules to package\n"
" [bold green]test[/bold green] - Run tests\n"
" [bold green]book[/bold green] - Build and manage Jupyter Book\n"
" [bold green]logo[/bold green] - Display the ASCII art logo\n\n"
" [bold green]logo[/bold green] - Learn about TinyTorch philosophy\n"
"[bold]Quick Start:[/bold]\n"
" [dim]tito system info[/dim] - Show system information\n"
" [dim]tito module status --metadata[/dim] - Module status with metadata\n"
" [dim]tito module view 01_setup[/dim] - Start coding in Jupyter Lab\n"
" [dim]tito checkpoint timeline[/dim] - Visual progress timeline\n"
" [dim]tito logo --animate[/dim] - Show animated logo\n\n"
"[bold]Get Help:[/bold]\n"
" [dim]tito system[/dim] - Show system subcommands\n"
" [dim]tito module[/dim] - Show module subcommands\n"