I pulled the source map for the Neopets renderer, and had Claude compare it to ours. It noticed the key issue responsible for a high number of unsolved rendering issues: we weren't setting up the `MotionGuidePlugin`, which I've never heard of before. Whoops! In addition to this, we made some other minor fixes for consistency: - Use whatever Stage object the library exports (will sometimes be StageGL) - Resize the stage rather than the clip (shouldn't matter?) - Send a callback to the library when done (I'm not aware of any anims that use this but some may!) The specific item I was debugging was "Food Fight Shower", and it works now! But I also know we've had a solid handful of similar inexplicable wild rendering bugs, which I imagine this solves as well. We might want to consider auditing our Known Glitches on SWF assets to see how many of them can be removed, now that this is resolved. |
||
|---|---|---|
| .devcontainer | ||
| .husky | ||
| app | ||
| bin | ||
| config | ||
| db | ||
| deploy | ||
| docs | ||
| lib | ||
| public | ||
| spec | ||
| test | ||
| vendor | ||
| .eslintrc.json | ||
| .gitignore | ||
| .rspec | ||
| .ruby-version | ||
| .yarnrc.yml | ||
| config.ru | ||
| falcon.rb | ||
| Gemfile | ||
| Gemfile.lock | ||
| LICENSE.md | ||
| package.json | ||
| Procfile.dev | ||
| Rakefile | ||
| README.md | ||
| yarn.lock | ||
Dress to Impress
Dress to Impress (DTI) is a tool for designing Neopets outfits. Load your pet, browse items, and see how they look together—all with a mobile-friendly interface!
Architecture Overview
DTI is a Rails application with a React-based outfit editor, backed by MySQL databases and a crowdsourced data collection system.
Core Components
- Rails backend (Ruby 3.4, Rails 8.0): Serves web pages, API endpoints, and manages data
- MySQL databases: Primary database (
openneo_impress) + legacy auth database (openneo_id) - React outfit editor: Embedded in
app/javascript/wardrobe-2020/, provides the main customization UI - Modeling system: Crowdsources pet/item appearance data by fetching from Neopets APIs when users load their pets
The Impress 2020 Complication
In 2020, we started a NextJS rewrite ("Impress 2020") to modernize the frontend. We've since consolidated back into Rails, but Impress 2020 still provides essential services:
- GraphQL API: Some outfit appearance data still loads via GraphQL (being migrated to Rails REST APIs)
- Image generation: Runs a headless browser to render outfit thumbnails and convert HTML5 assets to PNGs
See docs/impress-2020-dependencies.md for migration status.
Key Concepts
Customization Data Model
The core data model powers outfit rendering and item compatibility. See docs/customization-architecture.md for details.
Quick summary:
body_idis the key compatibility constraint (not species or color directly)- Items have different
swf_assets(visual layers) for different bodies - Restrictions are subtractive: start with all layers, hide some based on zone restrictions
- Data is crowdsourced through "modeling" (users loading pets to contribute appearance data)
Modeling (Crowdsourced Data)
DTI doesn't pre-populate item/pet data. Instead:
- User loads a pet (via pet name lookup)
- DTI fetches appearance data from Neopets APIs (legacy Flash/AMF protocol)
- New
SwfAssetrecords and relationships are created - Over time, the database learns which items fit which pet bodies
This "self-sustaining" approach means the site stays up-to-date as Neopets releases new content, without manual data entry.
Directory Map
Key Application Files
app/
├── controllers/
│ ├── outfits_controller.rb # Outfit editor + CRUD
│ ├── items_controller.rb # Item search, pages, and JSON APIs
│ ├── pets_controller.rb # Pet loading (triggers modeling)
│ └── closet_hangers_controller.rb # User item lists ("closets")
│
├── models/
│ ├── item.rb # Items + compatibility prediction logic
│ ├── pet_type.rb # Species+Color combinations (has body_id)
│ ├── pet_state.rb # Visual variants (pose/gender/mood)
│ ├── swf_asset.rb # Visual layers (biology/object)
│ ├── outfit.rb # Saved outfits + rendering logic (visible_layers)
│ ├── alt_style.rb # Alternative pet appearances (Nostalgic, etc.)
│ └── pet/
│ └── modeling_snapshot.rb # Processes Neopets API data into models
│
├── services/
│ ├── neopets/
│ │ ├── custom_pets.rb # Neopets AMF/Flash API client (pet data)
│ │ ├── nc_mall.rb # NC Mall item scraping
│ │ └── neopass.rb # NeoPass OAuth integration
│ ├── neopets_media_archive.rb # Local mirror of images.neopets.com
│ └── lebron_nc_values.rb # NC item trading values (external API)
│
├── javascript/
│ ├── wardrobe-2020/ # React outfit editor (extracted from Impress 2020)
│ │ ├── loaders/ # REST API calls (migrated from GraphQL)
│ │ ├── WardrobePage/ # Main editor UI
│ │ └── components/ # Shared React components
│ └── application.js # Rails asset pipeline entrypoint
│
└── views/
├── outfits/
│ └── edit.html.haml # Outfit editor page (loads React app)
├── items/
│ └── show.html.haml # Item detail page
└── closet_hangers/
└── index.html.haml # User closet/item lists
Configuration & Docs
config/
├── routes.rb # All Rails routes
├── database.yml # Multi-database setup (main + openneo_id)
└── environments/
└── *.rb # Env-specific config (incl. impress_2020_origin)
Documentation:
- docs/customization-architecture.md - Deep dive into data model & rendering
- docs/impress-2020-dependencies.md - What still depends on Impress 2020 service
Tests:
test/- Test::Unit tests (privacy features)spec/- RSpec tests (models, services, integrations)- Coverage is focused on key areas: modeling, prediction logic, external APIs
- Not comprehensive, but thorough for critical behaviors
Tech Stack
- Backend: Ruby on Rails (Ruby 3.4, Rails 8.0)
- Frontend: Mix of Rails views (Turbo/HAML) and React (for outfit editor)
- Database: MySQL (two databases:
openneo_impress,openneo_id) - Styling: CSS, Sass (moving toward modern Rails conventions)
- External Integrations:
- Neopets.com: Legacy Flash/AMF protocol for pet appearance data (modeling)
- Neopets NC Mall: Web scraping for NC item availability/pricing
- NeoPass: OAuth integration for Neopets account linking
- Neopets Media Archive: Local filesystem mirror of
images.neopets.com(never discards old files) - Lebron's NC Values: Third-party API for NC item trading values (lebron-values.netlify.app)
- Impress 2020: GraphQL for some outfit data, image generation service (being phased out)
Development Notes
OpenNeo ID Database
The openneo_id database is a legacy from when authentication was a separate service ("OpenNeo ID") meant to unify auth across multiple OpenNeo projects. DTI was the only project that succeeded, so the apps were merged—but the database split remains for now.
Implications:
- Rails is configured for multi-database mode
- User auth models live in
auth_user.rband connect toopenneo_id - ⚠️ CRITICAL: Impress 2020 also directly accesses both
openneo_impressandopenneo_iddatabases via SQL - Database migrations affecting these schemas must consider Impress 2020's direct access
- See docs/impress-2020-dependencies.md for full details on this dependency
Rails/React Hybrid
Most pages are traditional Rails views using Turbo for interactivity. The outfit editor (/outfits/new) is a full React app that:
- Loads into a
#wardrobe-2020-rootdiv - Uses React Query for data fetching
- Calls both Rails REST APIs (in
loaders/) and Impress 2020 GraphQL (being migrated)
The goal is to simplify this over time—either consolidate into Rails+Turbo, or commit fully to React. For now, we're in a hybrid state.
Deployment
- Main app: VPS running Rails (Puma, MySQL)
- Impress 2020: Separate VPS in same datacenter (NextJS, GraphQL, headless browser for images)
- Shared databases: Both services directly access the same MySQL databases over the network
openneo_impress- Main application dataopenneo_id- Authentication data- ⚠️ Any database schema changes must be compatible with both services
Project maintained by @matchu • OpenNeo.net