From Aspen to the Swiss Alps, from Deer Valley to Davos we can build an itinerary based on your ski vacation dreams. We’ll secure your accommodations, rentals, ski school, and lift tickets. All you have to do is pack. Let us show you the Professionally Planned difference.
Check out our customizable packing list for suggestions of what to pack for your ski experience.
document.addEventListener("DOMContentLoaded", function() {
const SHEET_URL = "https://api.sheetbest.com/sheets/a1b91312-947f-4689-b10a-1ab876c556af";
function randomPick(arr) {
return arr[Math.floor(Math.random()*arr.length)];
}
async function fetchItems() {
const res = await fetch(SHEET_URL);
const data = await res.json();
return data; // array of items
}
function pickItem(items, category, weather, occasion=null, excludeTypes=[]) {
let filtered = items.filter(i => i.Category === category);
if(weather) filtered = filtered.filter(i => i['Suitable Weather']?.includes(weather));
if(occasion) filtered = filtered.filter(i => i['Occasion']?.includes(occasion));
if(excludeTypes.length) filtered = filtered.filter(i => !excludeTypes.includes(i[`${category} Type`] || i.Type));
return filtered.length ? randomPick(filtered) : null;
}
async function generateOutfit() {
const weather = document.getElementById("weatherOption").value;
const items = await fetchItems();
let outfit = [];
// PICK dress OR top+bottom
let dress = pickItem(items, "Dress", weather);
if(dress) {
outfit.push(dress);
} else {
let top = pickItem(items, "Top", weather);
let bottom = pickItem(items, "Pants", weather) || pickItem(items, "Skirt", weather);
if(top) outfit.push(top);
if(bottom) outfit.push(bottom);
}
// Layer rules
let excludeLayers = [];
const topOrDress = outfit.find(i => i.Category === "Top" || i.Category === "Dress");
if(topOrDress?.['Top Type']?.toLowerCase()?.includes("sweater") || topOrDress?.['Dress Type']?.toLowerCase()?.includes("sweater")) {
excludeLayers = ["vest","cardigan","blazer","sweater vest"];
}
let layer = pickItem(items, "Layers", weather, null, excludeLayers);
if(layer) outfit.push(layer);
// Cold / Freezing coat rule
if(["Cold","Freezing"].includes(weather)) {
let coat = items.find(i => i['Layers Type']?.toLowerCase() === "coat");
if(coat) outfit.push(coat);
if(layer && ["blazer","shacket","jacket","puffer vest"].includes(layer['Layers Type']?.toLowerCase())) {
outfit = outfit.filter(i => i !== layer);
}
}
// Shoes
let shoes = pickItem(items, "Shoes", weather);
if(shoes && shoes['Shoes Type']?.toLowerCase().includes("rain boots") && 0 /* skip rain check for now */ < 80) {
shoes = pickItem(items, "Shoes", weather, null, ["rain boots"]);
}
if(shoes) outfit.push(shoes);
// Purse
let purse = pickItem(items, "Purse", weather);
if(purse) outfit.push(purse);
// Accessories (max 3, 2 for loungewear)
const isLoungewear = outfit.some(i => i.Occasion?.toLowerCase()?.includes("loungewear"));
const maxAccessories = isLoungewear ? 2 : 3;
let accessories = [];
const accCandidates = items.filter(i => i.Category === "Accessories");
while(accessories.length < maxAccessories) {
let acc = randomPick(accCandidates);
if(!acc) break;
if(!accessories.find(a=>a['Accessories Type']===acc['Accessories Type'])) {
if(acc['Accessories Type']?.toLowerCase()==="scarf" && accessories.find(a=>a['Accessories Type']?.toLowerCase()==="necklace")) continue;
if(acc['Accessories Type']?.toLowerCase()==="necklace" && accessories.find(a=>a['Accessories Type']?.toLowerCase()==="scarf")) continue;
if(acc['Accessories Type']?.toLowerCase()==="hat" && outfit.some(i=>i.Occasion?.toLowerCase()?.includes("special occasion"))) continue;
accessories.push(acc);
}
}
outfit.push(...accessories);
// Display outfit
const container = document.getElementById("outfit-results");
container.innerHTML = outfit.filter(Boolean).map(i =>
`
${i['Dress Type'] || i['Top Type'] || i['Pants Type'] || i['Layers Type'] || i['Accessories Type'] || i['Purse Type'] || i['Shoes Type'] || i.Type}
${i.Category}
`
).join("");
}
document.getElementById("generate").addEventListener("click", generateOutfit);
});