This commit is contained in:
2026-10-05 13:52:45 -04:00
parent 9eb71e9855
commit e90ebde399
34 changed files with 465 additions and 581 deletions
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Inter","role":"body"},{"family":"Roboto Condensed","role":"heading"}],"colors":{"primary":"#E8423B","secondary":"#40A9FF","accent":"#E8423B","background":"#FFFFFF","textPrimary":"#313130","link":"#3858E9"},"typography":{"fontFamilies":{"primary":"Inter","heading":"Roboto Condensed"},"fontStacks":{"heading":["Inter","sans-serif"],"body":["Times New Roman"],"paragraph":["Inter","sans-serif"]},"fontSizes":{"h1":"92.16px","h2":"92.16px","body":"20.736px"}},"spacing":{"baseUnit":4,"borderRadius":"2px"},"components":{"buttonPrimary":{"background":"#FFFFFF","textColor":"#E8423B","borderRadius":"0px","borderRadiusCorners":{"topLeft":"0px","topRight":"0px","bottomRight":"0px","bottomLeft":"0px"},"shadow":"none"}},"images":{"logo":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/logo.svg","favicon":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/favicons/favicon.ico","ogImage":null,"logoHref":"https://www.albinigroup.com/en/","logoAlt":"Albini Group Logo"},"personality":{"tone":"professional","energy":"medium","targetAudience":"business professionals"},"designSystem":{"framework":"custom","componentLibrary":""},"confidence":{"buttons":0.8,"colors":0.9,"overall":0.8500000000000001},"brandName":"Homepage","logo":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/logo.svg"},"metadata":{"viewport":"width=device-width, initial-scale=1","theme-color":"#060606","generator":"WPML ver:4.6.11 stt:1,27;","language":"en-US","robots":"max-image-preview:large","title":"Homepage","msapplication-TileImage":"https://www.albinigroup.com/wp-content/uploads/2024/07/android-chrome-512x512-2-300x300.png","format-detection":"telephone=no","favicon":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/favicons/favicon.ico","scrapeId":"01a10843-3309-76f1-87e6-86b2fe6dff94","sourceURL":"https://www.albinigroup.com/en/","url":"https://www.albinigroup.com/en/","statusCode":200,"contentType":"text/html; charset=UTF-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"687378ad-1338-4a4e-890d-8f67d61cc28a","creditsUsed":1,"concurrencyLimited":false}}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Helvetica Neue","role":"body"},{"family":"Palatino Linotype","role":"heading"}],"colors":{"primary":"#2563EB","secondary":"#9CA3AF","accent":"#2F2727","background":"#2F2727","textPrimary":"#2F2727","link":"#6B7280"},"typography":{"fontFamilies":{"primary":"Helvetica Neue","heading":"Palatino Linotype"},"fontStacks":{"heading":["__swiss_888950","__swiss_Fallback_888950","Helvetica Neue","Helvetica","Arial","sans-serif"],"body":["__swiss_888950","__swiss_Fallback_888950","Helvetica Neue","Helvetica","Arial","sans-serif"],"paragraph":["__swiss_888950","__swiss_Fallback_888950","Helvetica Neue","Helvetica","Arial","sans-serif"]},"fontSizes":{"h1":"16px","h2":"48px","body":"16px"}},"spacing":{"baseUnit":4,"borderRadius":"0px"},"components":{"input":{"background":"#FFFFFF","textColor":"#2F2727","borderColor":"#D5D4D4","borderRadius":"9999px","borderRadiusCorners":{"topLeft":"9999px","topRight":"9999px","bottomRight":"9999px","bottomLeft":"9999px"},"shadow":"none"},"buttonPrimary":{"background":"#2F2727","textColor":"#FFFFFF","borderRadius":"9999px","borderRadiusCorners":{"topLeft":"9999px","topRight":"9999px","bottomRight":"9999px","bottomLeft":"9999px"},"shadow":"none"},"buttonSecondary":{"background":"#F5F5F5","textColor":"#2F2727","borderRadius":"9999px","borderRadiusCorners":{"topLeft":"9999px","topRight":"9999px","bottomRight":"9999px","bottomLeft":"9999px"},"shadow":"none"}},"images":{"logo":"https://content.camirafabrics.com/media/2gcngglc/camira-logo-light.svg?q=100&width=3840","favicon":"https://www.camirafabrics.com/favicon.ico","ogImage":null,"logoHref":"https://www.camirafabrics.com/us?meta=JTdCJTdE","logoAlt":"Camira Logo Light"},"personality":{"tone":"professional","energy":"medium","targetAudience":"business professionals"},"designSystem":{"framework":"tailwind","componentLibrary":""},"confidence":{"buttons":0.9,"colors":0.9,"overall":0.9},"brandName":"Camira","logo":"https://content.camirafabrics.com/media/2gcngglc/camira-logo-light.svg?q=100&width=3840"},"metadata":{"robots":"noindex","viewport":["width=device-width, initial-scale=1","width=device-width,initial-scale=1"],"title":"Camira | Leading Supplier of Contract Fabrics and Upholstery Solutions","google-site-verification":"9h1IFVr9Fye0MSBgBlu-rt6V1e3C34bL0IbfI6HsTLY","description":"Discover Camira's extensive range of contract fabrics, ideal for commercial and residential interiors. Explore our high-quality upholstery solutions tailored for offices, hotels, and more","language":"en-US","favicon":"https://www.camirafabrics.com/favicon.ico","scrapeId":"01a10842-a7a3-751a-8edc-a88a06d5d185","sourceURL":"https://www.camirafabrics.com/us","url":"https://www.camirafabrics.com/us","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"1372bc68-234b-44eb-828a-ef652391b19a","creditsUsed":1,"concurrencyLimited":true,"concurrencyQueueDurationMs":13158},"warning":"This scrape job was throttled at your current concurrency limit. If you'd like to scrape faster, you can upgrade your plan."}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Kvadrat Neuzeit S","role":"body"},{"family":"Arial","role":"body"}],"colors":{"primary":"#000000","accent":"#000000","background":"#FFFFFF","textPrimary":"#231F20","link":"#000000"},"typography":{"fontFamilies":{"primary":"Kvadrat Neuzeit S","heading":"Kvadrat Neuzeit S"},"fontStacks":{"heading":["kvadrat_neuzeit_s","Arial","sans-serif"],"body":["kvadrat_neuzeit_s","Arial","sans-serif"],"paragraph":["kvadrat_neuzeit_s","Arial","sans-serif"]},"fontSizes":{"h1":"16px","h2":"25px","body":"16px"}},"spacing":{"baseUnit":8,"borderRadius":"0px"},"components":{"input":{"background":"#FFFFFF","textColor":"#231F20","borderColor":null,"borderRadius":"22.5px","borderRadiusCorners":{"topLeft":"22.5px","topRight":"22.5px","bottomRight":"22.5px","bottomLeft":"22.5px"},"shadow":"none"}},"images":{"logo":"https://www.kvadrat.dk/apple-touch-icon-180x180-precomposed.png","favicon":"https://www.kvadrat.dk/apple-touch-icon-precomposed.png","ogImage":null,"logoAlt":"Kvadrat"},"personality":{"tone":"professional","energy":"medium","targetAudience":"design professionals"},"designSystem":{"framework":"custom","componentLibrary":""},"confidence":{"buttons":0,"colors":0.9,"overall":0.45},"brandName":"Kvadrat","logo":"https://www.kvadrat.dk/apple-touch-icon-180x180-precomposed.png"},"metadata":{"title":"Kvadrat - The global design textile company","ogTitle":"Kvadrat - The global design textile company","HandheldFriendly":"true","apple-mobile-web-app-title":"Kvadrat","ogImage":"","og:type":"website","og:description":"Immerse yourself in a world of inspiring contemporary textiles with Kvadrat. Explore our elegant upholstery, captivating curtains, premium rugs, and high-quality and sustainable solutions and bring your interior projects to life.","viewport":["width=device-width, initial-scale=1.0","width=device-width,initial-scale=1,user-scalable=yes","width=device-width,initial-scale=1"],"language":"en","og:image:height":"630","googlebot":"noindex,indexifembedded","description":"Immerse yourself in a world of inspiring contemporary textiles with Kvadrat. Explore our elegant upholstery, captivating curtains, premium rugs, and high-quality and sustainable solutions and bring your interior projects to life.","mobile-web-app-capable":"yes","apple-mobile-web-app-capable":"yes","fragment":"!","apple-mobile-web-app-status-bar-style":"black","ogDescription":"Immerse yourself in a world of inspiring contemporary textiles with Kvadrat. Explore our elegant upholstery, captivating curtains, premium rugs, and high-quality and sustainable solutions and bring your interior projects to life.","robots":["index, follow","index, follow"],"og:title":"Kvadrat - The global design textile company","google-site-verification":"P2D50rlQuBWe5zCrhyaWdg25yf1EPkUj_T0QSD4Ux30","og:url":"/en","og:image:width":"1200","og:image":"","ogUrl":"/en","favicon":"https://www.kvadrat.dk/touch-icon-192x192.png","scrapeId":"01a10842-a78e-726d-8967-816fd3028c2a","sourceURL":"https://www.kvadrat.dk/en","url":"https://www.kvadrat.dk/en","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"88c37cd9-deae-4af8-aa23-4a7ab4e5fba9","creditsUsed":1,"concurrencyLimited":false}}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"MaharamNeue-Medium","role":"heading"},{"family":"MaharamNeue-Regular","role":"body"}],"colors":{"primary":"#1B7F9E","secondary":"#C18610","accent":"#07893E","background":"#EDEDE8","textPrimary":"#000000","link":"#07893E"},"typography":{"fontFamilies":{"primary":"MaharamNeue-Regular","heading":"MaharamNeue-Medium"},"fontStacks":{"heading":["MaharamNeue-Regular","Helvetica","Arial","sans-serif"],"body":["MaharamNeue-Regular","Helvetica","Arial","sans-serif"],"paragraph":["MaharamNeue-Medium","Helvetica","Arial","sans-serif"]},"fontSizes":{"h1":"14px","h2":"14px","body":"9px"}},"spacing":{"baseUnit":4,"borderRadius":"4px"},"components":{"input":{"background":"#FFFFFF","textColor":"#000000","borderColor":null,"borderRadius":"5px","borderRadiusCorners":{"topLeft":"5px","topRight":"5px","bottomRight":"5px","bottomLeft":"5px"},"shadow":"none"}},"images":{"logo":"https://www.maharam.com/apple-touch-icon.png","favicon":"https://www.maharam.com/assets/favicon-f4f91d83b92be42dcd21f5946f92e54c048fba408c22f621e58c1ac167f40f61.ico","ogImage":null,"logoAlt":"Maharam"},"personality":{"tone":"professional","energy":"medium","targetAudience":"design professionals"},"designSystem":{"framework":"custom","componentLibrary":""},"confidence":{"buttons":0,"colors":0.95,"overall":0.475},"brandName":"Maharam","logo":"https://www.maharam.com/apple-touch-icon.png"},"metadata":{"robots":"follow,index","language":"en","copyright":"Copyright 2026, Maharam","description":"Maharam is North America's leading creator of textiles for commercial and residential interiors.","keywords":"Maharam, Knoll Textiles, Edelman, Textiles, Fabrics, Wallcoverings, Privacy Curtains, Window Coverings, Drapery, Draperies, Digital Projects, Maharam Digital Projects, Panel, Wall Systems, Upholstery, Commercial, Contract, Residential, Interiors, Healthcare, Hospitality, Corporate, Collaboration, Twentieth Century, Agenda, Leather, Leather Tiles, Hides","revisit-after":"3 days","msapplication-config":"none","title":"Maharam","viewport":"width=device-width, initial-scale=1, shrink-to-fit=no","csrf-param":"authenticity_token","csrf-token":"RGnSJ-2JJQtSeKNBhGhi83R4MK-_INpAFYbIJ3oTKb8mZhGaapWN5MaGCQbFdeuvqDUnDre-FVlo80aieCFOWQ","favicon":"https://www.maharam.com/assets/favicon-f4f91d83b92be42dcd21f5946f92e54c048fba408c22f621e58c1ac167f40f61.ico","scrapeId":"01a10842-a79d-771c-ad1e-215713ca4db4","sourceURL":"https://www.maharam.com/","url":"https://www.maharam.com/","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"f1f9c1aa-aeeb-4a2b-950e-cd5df6f4530f","creditsUsed":1,"concurrencyLimited":true,"concurrencyQueueDurationMs":6122},"warning":"This scrape job was throttled at your current concurrency limit. If you'd like to scrape faster, you can upgrade your plan."}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Noto Sans","role":"body"}],"colors":{"primary":"#00378C","secondary":"#0D6EFD","accent":"#00378C","background":"#FFFFFF","textPrimary":"#000000","link":"#003366"},"typography":{"fontFamilies":{"primary":"Noto Sans","heading":"Noto Sans"},"fontStacks":{"heading":["Noto Sans","sans-serif"],"body":["Noto Sans","sans-serif"],"paragraph":["Noto Sans","sans-serif"]},"fontSizes":{"h1":"48px","h2":"48px","body":"20px"}},"spacing":{"baseUnit":4,"borderRadius":"3px"},"components":{"buttonPrimary":{"background":"#00378C","textColor":"#FFFFFF","borderColor":"#00378C","borderRadius":"50px","borderRadiusCorners":{"topLeft":"50px","topRight":"50px","bottomRight":"50px","bottomLeft":"50px"},"shadow":"none"},"buttonSecondary":{"background":"#000000","textColor":"#FFFFFF","borderRadius":"0px","borderRadiusCorners":{"topLeft":"0px","topRight":"0px","bottomRight":"0px","bottomLeft":"0px"},"shadow":"none"}},"images":{"logo":"https://www.milliken.com/-/media/milliken/footer-v2/milliken-logo-footer.svg","favicon":"https://www.milliken.com/assets/images/favicons/milliken-favicon.ico","ogImage":"https://contenthub.milliken.com/api/public/content/142bbadfbf6c4309a5b627a101800bac?v=eaf7ac01&t=W1440xH720","logoHref":"https://www.milliken.com/en-us/","logoAlt":"Milliken & Company logo"},"personality":{"tone":"professional","energy":"medium","targetAudience":"business professionals and industries seeking high-performance textiles"},"designSystem":{"framework":"bootstrap","componentLibrary":""},"confidence":{"buttons":0.95,"colors":0.9,"overall":0.925},"brandName":"High","logo":"https://www.milliken.com/-/media/milliken/footer-v2/milliken-logo-footer.svg"},"metadata":{"description":"Discover Milliken’s high-performance textiles for apparel, automotive, military, and industrial markets engineered through material science and PFAS-free innovation.","ogTitle":"High-Performance Textiles & Fabric Innovation | Milliken","viewport":"width=device-width, initial-scale=1, shrink-to-fit=no","title":"High-Performance Textiles & Fabric Innovation | Milliken","facebook-domain-verification":"bb8bw417fkjl8mfe669ii98qp9i87s","og:title":"High-Performance Textiles & Fabric Innovation | Milliken","language":"en-US","og:description":"Discover","ogDescription":"Discover","keywords":"","ogUrl":"https://www.milliken.com/en-us/textiles","og:type":"website","og:image:height":"660","og:image:width":"1920","ogImage":"https://contenthub.milliken.com/api/public/content/142bbadfbf6c4309a5b627a101800bac?v=eaf7ac01&t=W1440xH720","og:image:alt":"Flame resist fabric testing with dummy being exposed to flames","og:url":"https://www.milliken.com/en-us/textiles","og:image":"https://contenthub.milliken.com/api/public/content/142bbadfbf6c4309a5b627a101800bac?v=eaf7ac01&t=W1440xH720","favicon":"https://www.milliken.com/assets/images/favicons/milliken-favicon.ico","scrapeId":"01a10843-32fe-73b8-b81f-534572f9f400","sourceURL":"https://textiles.milliken.com/","url":"https://www.milliken.com/en-us/textiles","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"bd4adbc8-3a41-484e-a57a-d8832a065cce","creditsUsed":1,"concurrencyLimited":false}}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

+3 -162
View File
@@ -10,8 +10,7 @@
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-router-dom": "^7.6.0",
"vgpu": "^0.5.0"
"react-router-dom": "^7.6.0"
},
"devDependencies": {
"@playwright/test": "^1.52.0",
@@ -793,31 +792,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@modelcontextprotocol/core": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0.tgz",
"integrity": "sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==",
"license": "MIT",
"dependencies": {
"zod": "^4.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@modelcontextprotocol/server": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0.tgz",
"integrity": "sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/core": "2.0.0",
"zod": "^4.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@napi-rs/lzma-linux-x64-gnu": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz",
@@ -1302,58 +1276,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@vgpu/adapter-mock": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/adapter-mock/-/adapter-mock-0.5.0.tgz",
"integrity": "sha512-YtgXOFn1qI+8oTJenG2wWbQPA28V0CfE5UJs5Xqbt6qyR/xaZ5LHH2XWTwFcjnqn2b1xQCyTatJCMyyOdweUnw==",
"license": "MIT",
"dependencies": {
"@vgpu/core": "0.5.0"
}
},
"node_modules/@vgpu/adapter-node": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/adapter-node/-/adapter-node-0.5.0.tgz",
"integrity": "sha512-lgzqFcLDejwRgwlaNStzkwLNU9b4aN2OoPpWqT1UyPmK521BSw2OIQKzAuDIkzNlREla6KNC12G6bthhOzZKzw==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@vgpu/core": "0.5.0",
"webgpu": "0.4.0"
}
},
"node_modules/@vgpu/core": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/core/-/core-0.5.0.tgz",
"integrity": "sha512-z80DHRHViv6+FKKkPzggEtT1ZZs/WCKRQbzJuwYdA135DZaSbCMoRK4anhM+I/nOHuDpf7H3xjkwE6rfolWZUw==",
"license": "MIT",
"dependencies": {
"@vgpu/wgsl": "0.5.0"
}
},
"node_modules/@vgpu/wgsl": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/wgsl/-/wgsl-0.5.0.tgz",
"integrity": "sha512-PDlDJem7J28C9bk+vPy2kYZEoW8+nYIx2oN4nu7/WF2V7ETx32BtmWcawwMbhiu/CVsobFafML0h0eqLRBNa3Q==",
"license": "MIT",
"dependencies": {
"@vgpu/wgsl-std": "0.5.0"
},
"peerDependencies": {
"@vgpu/adapter-node": ">=0.1.6 <1.0.0 || ^0.5.0-rc.0"
},
"peerDependenciesMeta": {
"@vgpu/adapter-node": {
"optional": true
}
}
},
"node_modules/@vgpu/wgsl-std": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/wgsl-std/-/wgsl-std-0.5.0.tgz",
"integrity": "sha512-NjMyJxwy4evFNCSqFQy4EqAbZ7iU+NUyJYyG9tLUhbdDLzBmfZlk1S3PyRZ9olBFFfEiVW2JNVw10maPKLEs1A==",
"license": "MIT"
},
"node_modules/@vitejs/plugin-react": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
@@ -1375,12 +1297,6 @@
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
"node_modules/@webgpu/types": {
"version": "0.1.72",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.72.tgz",
"integrity": "sha512-0cF7RFM2edNoiIS1ODJp0/Gzv4/xSXhwoR0YCza+OWpJWtn4wmo9DvK91aLlH9+uUnwIriP7ZiC3WitmyhuzBw==",
"license": "BSD-3-Clause"
},
"node_modules/baseline-browser-mapping": {
"version": "2.11.21",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz",
@@ -1473,6 +1389,7 @@
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -1635,6 +1552,7 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -1686,18 +1604,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pixelmatch": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.2.0.tgz",
"integrity": "sha512-xhcb4yHu9sM/G7foGzoLtXYcC0zHEaOXXjRKhGup0fw78Nf2Tkiapv4EQyMzrbcmQPsllAI7DbFY2UT7PlI9Pg==",
"license": "ISC",
"dependencies": {
"pngjs": "^7.0.0"
},
"bin": {
"pixelmatch": "bin/pixelmatch"
}
},
"node_modules/playwright": {
"version": "1.63.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
@@ -1727,15 +1633,6 @@
"node": ">=20"
}
},
"node_modules/pngjs": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
"license": "MIT",
"engines": {
"node": ">=14.19.0"
}
},
"node_modules/postcss": {
"version": "8.5.28",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
@@ -1960,36 +1857,6 @@
"browserslist": ">= 4.21.0"
}
},
"node_modules/vgpu": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/vgpu/-/vgpu-0.5.0.tgz",
"integrity": "sha512-isQfMHRTysYFfT8UWTzqQI/ROw2L7lVkj7xoUJlvIF6FjYxBNS/YNG7qp3tZ7ZvZZ3uwYjso+geQv/bEq5Hl3w==",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/server": "2.0.0",
"@vgpu/adapter-mock": "0.5.0",
"@vgpu/adapter-node": "0.5.0",
"@vgpu/core": "0.5.0",
"@vgpu/wgsl": "0.5.0",
"@vgpu/wgsl-std": "0.5.0",
"@webgpu/types": "^0.1.69",
"pixelmatch": "^7.2.0",
"pngjs": "^7.0.0",
"wgpu-matrix": "^3.4.2",
"zod": "^4.4.3"
},
"bin": {
"vgpu": "bin/vgpu.js"
},
"peerDependencies": {
"three": ">=0.180.0 <0.200.0"
},
"peerDependenciesMeta": {
"three": {
"optional": true
}
}
},
"node_modules/vite": {
"version": "6.4.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
@@ -2065,38 +1932,12 @@
}
}
},
"node_modules/webgpu": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/webgpu/-/webgpu-0.4.0.tgz",
"integrity": "sha512-F5pimn3Aoi0zWjuRdiVs5TnrUwSzD2lESBohsIUsqyitWkGRQlXU2fhV6ycXlQTa1bvAf3sjqiUpBEpmSQ5ptA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@webgpu/types": "^0.1.69",
"debug": "^4.4.0"
}
},
"node_modules/wgpu-matrix": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/wgpu-matrix/-/wgpu-matrix-3.4.2.tgz",
"integrity": "sha512-IfZFbG7olEYBD76VCZy2TzqM57GKy3LT++AZh37tMHPPByO6R2h61zXGBZFNPi2IzxNivNi8y5dvze5PjaczjA==",
"license": "MIT"
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true,
"license": "ISC"
},
"node_modules/zod": {
"version": "4.6.5",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
"integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}
+1 -2
View File
@@ -12,8 +12,7 @@
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-router-dom": "^7.6.0",
"vgpu": "^0.5.0"
"react-router-dom": "^7.6.0"
},
"devDependencies": {
"@playwright/test": "^1.52.0",
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +1,8 @@
Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts)
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic) NotoSans-Italic[wdth,wght].ttf: Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL
http://scripts.sil.org/OFL
-----------------------------------------------------------
Binary file not shown.
@@ -1,8 +1,8 @@
Copyright 2022 The Instrument Serif Project Authors (https://github.com/Instrument/instrument-serif)
Copyright 2011 Google Inc. All Rights Reserved. RobotoCondensed-Italic[wght].ttf: Copyright 2011 Google Inc. All Rights Reserved.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL
http://scripts.sil.org/OFL
-----------------------------------------------------------
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

+14 -15
View File
@@ -1,21 +1,14 @@
@font-face {
font-family: "Instrument Serif";
src: url("/fonts/instrument-serif-regular.ttf") format("truetype");
font-weight: 400;
font-family: "Roboto Condensed";
src: url("/fonts/roboto-condensed.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Instrument Serif";
src: url("/fonts/instrument-serif-italic.ttf") format("truetype");
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "DM Sans";
src: url("/fonts/dm-sans.woff2") format("woff2");
font-weight: 100 1000;
font-family: "Noto Sans";
src: url("/fonts/noto-sans.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@@ -26,8 +19,10 @@
--line: #d9d9cf;
--wash: #ecebe4;
--accent: #8f725c;
--serif: "Instrument Serif", Georgia, serif;
--sans: "DM Sans", Arial, sans-serif;
--industrial: #496678;
--industrial-deep: #273f4d;
--serif: "Roboto Condensed", "Arial Narrow", sans-serif;
--sans: "Noto Sans", Arial, sans-serif;
--mono: "Courier New", monospace;
--page-gutter: clamp(20px, 4vw, 72px);
color-scheme: light;
@@ -48,6 +43,10 @@ body {
margin: 0;
min-width: 320px;
}
em {
font-style: normal;
font-weight: 600;
}
button,
input,
textarea,
+7 -5
View File
@@ -10,13 +10,15 @@ export default function Gallery({ preview = false }) {
<section className="gallery" id="developments" tabIndex={-1}>
<SectionHeading
centered
label="Selected developments"
label={
preview ? "Featured fabric developments" : "Selected developments"
}
title={
preview ? (
<>
Structure changes
What we make.
<br />
<em>everything.</em>
<em>What we can develop.</em>
</>
) : (
<>
@@ -29,12 +31,12 @@ export default function Gallery({ preview = false }) {
>
<p className="gallery__intro">
{preview
? "From subtle surface structures to more expressive knitted textures, different yarn combinations and machine setups produce entirely different fabric characteristics."
? "A selection of knitted structures showing how yarn, composition and machine setup shape the final fabric character."
: "Selected developments are processed separately as reference samples to explore how a construction can translate after dyeing and finishing. RRS commercially manufactures greige fabric only."}
</p>
{preview && (
<Action to="/fabrics#developments" variant="outline">
View developments
Explore all fabrics
</Action>
)}
</SectionHeading>
+13 -30
View File
@@ -31,7 +31,9 @@
top: 10px;
}
.site-header {
border-top: 4px solid var(--industrial);
border-bottom: 1px solid var(--line);
background: #faf9f5;
}
.site-header__inner {
display: flex;
@@ -44,27 +46,11 @@
.brand {
display: inline-flex;
align-items: center;
gap: 16px;
text-decoration: none;
color: var(--ink);
}
.brand__mark {
font-family: var(--serif);
font-size: 42px;
font-weight: 600;
line-height: 1;
letter-spacing: -0.065em;
}
.brand__period {
color: var(--accent);
}
.brand__name {
border-left: 1px solid var(--line);
padding-left: 16px;
font-size: 9px;
line-height: 1.65;
text-transform: uppercase;
letter-spacing: 0.12em;
.brand__logo {
display: block;
width: 92px;
height: auto;
}
.site-nav {
display: flex;
@@ -100,15 +86,15 @@
gap: 30px;
margin-left: 45px;
padding: 12px 20px;
border: 1px solid var(--ink);
border: 1px solid var(--industrial-deep);
border-radius: 30px;
color: var(--ink);
background: var(--industrial-deep);
color: var(--paper);
text-decoration: none;
font-size: 11px;
}
.site-nav__contact:hover {
background: var(--ink);
color: var(--paper);
background: var(--industrial);
}
.site-header__toggle {
display: none;
@@ -209,7 +195,7 @@
display: flex;
align-items: center;
min-height: 420px;
background: var(--ink);
background: var(--industrial-deep);
color: var(--paper);
padding: 64px;
border-radius: 6px;
@@ -282,11 +268,8 @@
flex-wrap: wrap;
gap: 0;
}
.brand__mark {
font-size: 35px;
}
.brand__name {
font-size: 8px;
.brand__logo {
width: 78px;
}
.site-header__toggle {
display: flex;
+9 -10
View File
@@ -7,14 +7,13 @@ import "./Layout.css";
function Brand() {
return (
<Link className="brand" to="/" aria-label="RRS home">
<span className="brand__mark">
RRS<span className="brand__period">.</span>
</span>
<span className="brand__name">
Radhe Radhe
<br />
Synthetics
</span>
<img
className="brand__logo"
src="/images/RRSLOGO.png"
alt="Radhe Radhe Synthetics"
width="1024"
height="809"
/>
</Link>
);
}
@@ -68,7 +67,7 @@ function Header() {
to="/contact#whatsapp"
onClick={closeMenu}
>
Let's talk <Arrow diagonal />
Request a quote <Arrow diagonal />
</Link>
</nav>
</div>
@@ -93,7 +92,7 @@ function Footer() {
))}
</nav>
<div className="site-footer__contact">
<span className="site-footer__label">Start a conversation</span>
<span className="site-footer__label">Commercial enquiries</span>
<Link className="site-footer__link" to="/contact#whatsapp">
WhatsApp <Arrow diagonal />
</Link>
+185 -62
View File
@@ -2,76 +2,124 @@
position: fixed;
inset: 0;
z-index: 1000;
display: grid;
grid-template-rows: auto 1fr;
overflow: hidden;
padding: clamp(24px, 3.5vw, 56px);
color: #f5f3ee;
background: #24231e;
transition:
opacity 650ms cubic-bezier(0.76, 0, 0.24, 1),
clip-path 650ms cubic-bezier(0.76, 0, 0.24, 1);
clip-path: inset(0);
color: var(--ink);
background: var(--paper);
}
.loader--closing {
opacity: 0;
clip-path: inset(0 0 100% 0);
pointer-events: none;
}
.loader__canvas,
.loader__veil {
.loader__scene {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.loader__canvas {
display: block;
opacity: 0;
transition: opacity 180ms ease-out;
}
.loader__canvas[data-ready="true"] {
opacity: 1;
}
.loader__veil {
background: linear-gradient(90deg, #17171238, transparent 45%, #17171238);
}
.loader__topline,
.loader__center {
position: relative;
.loader__yarns {
position: absolute;
z-index: 1;
top: 0;
left: 50%;
width: min(72vw, 920px);
height: 34%;
overflow: visible;
transform: translateX(-50%);
}
.loader__topline {
.loader__yarns path {
fill: none;
stroke: var(--industrial);
stroke-width: 5;
stroke-linecap: round;
vector-effect: non-scaling-stroke;
opacity: 0;
stroke-dasharray: 1200;
stroke-dashoffset: 1200;
animation: yarn-feed 780ms 480ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.loader__yarns path:nth-child(2),
.loader__yarns path:nth-child(6) {
stroke: var(--accent);
animation-delay: 580ms;
}
.loader__yarns path:nth-child(3),
.loader__yarns path:nth-child(5) {
animation-delay: 660ms;
}
.loader__yarns path:nth-child(4) {
stroke: var(--ink);
stroke-width: 6;
animation-delay: 540ms;
}
.loader__machine {
position: absolute;
z-index: 2;
inset: 5% 0 7%;
display: grid;
place-items: center;
clip-path: inset(0 0 100%);
animation: machine-reveal 900ms 680ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.loader__machine-image {
display: block;
width: auto;
height: min(84vh, 1050px);
max-width: 84vw;
object-fit: contain;
filter: grayscale(1) contrast(1.08);
transform: scale(1.04);
animation: machine-colour 850ms 1050ms ease-out forwards;
}
.loader__brand {
position: absolute;
z-index: 4;
left: 50%;
bottom: clamp(18px, 2.2vw, 36px);
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.16em;
text-transform: uppercase;
padding: 10px 18px;
border: 1px solid #282a2324;
border-radius: 999px;
background: #f5f3eee8;
backdrop-filter: blur(8px);
opacity: 0;
transform: translate(-50%, 14px);
animation: brand-arrive 450ms 1500ms ease-out forwards;
}
.loader__center {
align-self: center;
justify-self: center;
text-align: center;
.loader__logo {
width: 82px;
height: auto;
}
.loader__eyebrow {
margin: 0 0 18px;
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.loader__title {
.loader__message {
margin: 0;
padding-left: 18px;
border-left: 1px solid var(--line);
font-family: var(--serif);
font-size: clamp(58px, 8.5vw, 132px);
font-weight: 400;
line-height: 0.84;
letter-spacing: -0.055em;
font-size: 18px;
line-height: 1.1;
white-space: nowrap;
}
.loader__title em {
font-weight: 400;
.loader__handoff {
position: absolute;
z-index: 10;
inset: 0;
background:
repeating-linear-gradient(115deg, transparent 0 8px, #f5f3ee13 8px 9px),
var(--industrial-deep);
transform: translateX(-101%);
will-change: transform;
}
.loader--covering {
pointer-events: none;
}
.loader--covering .loader__handoff {
animation: handoff-cover 450ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
}
.loader--revealing {
background: transparent;
pointer-events: none;
}
.loader--revealing .loader__scene {
opacity: 0;
}
.loader--revealing .loader__handoff {
transform: translateX(0);
animation: handoff-reveal 600ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
}
.loader__announcement {
position: absolute;
@@ -81,16 +129,91 @@
clip-path: inset(50%);
white-space: nowrap;
}
@media (max-width: 600px) {
.loader__title {
font-size: clamp(54px, 19vw, 86px);
@keyframes yarn-feed {
0% {
opacity: 0;
stroke-dashoffset: 1200;
}
.loader__topline span:last-child {
display: none;
4% {
opacity: 0.82;
}
100% {
opacity: 0.82;
stroke-dashoffset: 0;
}
}
@keyframes machine-reveal {
to {
clip-path: inset(0);
}
}
@keyframes machine-colour {
to {
filter: grayscale(0) contrast(1);
transform: scale(1);
}
}
@keyframes brand-arrive {
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
@keyframes handoff-cover {
to {
transform: translateX(0);
}
}
@keyframes handoff-reveal {
to {
transform: translateX(101%);
}
}
@media (max-width: 600px) {
.loader__yarns {
width: 108vw;
height: 32%;
}
.loader__machine {
inset: 9% 0 12%;
}
.loader__machine-image {
width: 98vw;
height: auto;
max-width: none;
}
.loader__brand {
bottom: 22px;
gap: 11px;
padding: 8px 12px;
}
.loader__logo {
width: 66px;
}
.loader__message {
padding-left: 11px;
font-size: 15px;
}
}
@media (prefers-reduced-motion: reduce) {
.loader {
transition: none;
.loader__yarns,
.loader__handoff {
display: none;
}
.loader__machine,
.loader__machine-image,
.loader__brand {
animation: none;
}
.loader__machine {
clip-path: inset(0);
}
.loader__machine-image {
filter: none;
transform: none;
}
.loader__brand {
opacity: 1;
transform: translate(-50%, 0);
}
}
+45 -79
View File
@@ -1,106 +1,72 @@
import { useEffect, useRef, useState } from "react";
import weaveShader from "../shaders/loader.wgsl?raw";
import { useEffect, useState } from "react";
import "./Loader.css";
export default function Loader() {
const canvasRef = useRef(null);
const [phase, setPhase] = useState("active");
useEffect(() => {
const reducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)",
).matches;
const closeTimer = window.setTimeout(
() => setPhase("closing"),
reducedMotion ? 0 : 1900,
const coveringTimer = window.setTimeout(
() => setPhase("covering"),
reducedMotion ? 0 : 2100,
);
const revealTimer = window.setTimeout(
() => setPhase("revealing"),
reducedMotion ? 25 : 2550,
);
const removeTimer = window.setTimeout(
() => setPhase("hidden"),
reducedMotion ? 50 : 2550,
reducedMotion ? 50 : 3150,
);
return () => {
window.clearTimeout(closeTimer);
window.clearTimeout(coveringTimer);
window.clearTimeout(revealTimer);
window.clearTimeout(removeTimer);
};
}, []);
useEffect(() => {
if (phase !== "active") return undefined;
let active = true;
let gpu;
let loop;
let unsubscribeResize;
async function renderWeave() {
try {
const { clock, effect, frameLoop, init, surface } = await import(
"vgpu"
);
gpu = await init({ powerPreference: "low-power" });
if (!active) return gpu.dispose();
const target = surface(gpu, canvasRef.current, { dpr: [1, 1.5] });
const weave = effect(gpu, weaveShader, {
set: { params: { time: 0, progress: 0, aspect: 1, padding: 0 } },
});
const timer = clock(gpu);
unsubscribeResize = target.onResize(({ width, height }) => {
weave.set({ params: { aspect: width / height } });
});
let presented = false;
loop = frameLoop(
gpu,
(frame) => {
weave.set({
params: {
time: timer.time,
progress: Math.min(1.2, timer.time / 1.8),
},
});
frame.pass(target, weave);
if (!presented) {
presented = true;
requestAnimationFrame(() => {
if (active) canvasRef.current.dataset.ready = "true";
});
}
},
{ fps: 30 },
);
} catch {
// A flat background remains when WebGPU is unavailable.
}
}
if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches)
renderWeave();
return () => {
active = false;
loop?.stop();
unsubscribeResize?.();
gpu?.dispose();
};
}, [phase]);
if (phase === "hidden") return null;
return (
<div className={`loader loader--${phase}`} aria-live="polite">
<canvas className="loader__canvas" ref={canvasRef} aria-hidden="true" />
<div className="loader__veil" aria-hidden="true" />
<div className="loader__topline">
<span>RRS / 1987</span>
<span>Surat, India</span>
<div className="loader__scene">
<svg
className="loader__yarns"
viewBox="0 0 1000 430"
preserveAspectRatio="none"
aria-hidden="true"
>
<path pathLength="1" d="M60 0 C90 150 120 285 180 430" />
<path pathLength="1" d="M205 0 C230 155 255 310 285 430" />
<path pathLength="1" d="M350 0 C365 170 380 320 395 430" />
<path pathLength="1" d="M500 0 L500 430" />
<path pathLength="1" d="M650 0 C635 170 620 320 605 430" />
<path pathLength="1" d="M795 0 C770 155 745 310 715 430" />
<path pathLength="1" d="M940 0 C910 150 880 285 820 430" />
</svg>
<div className="loader__machine" aria-hidden="true">
<img
className="loader__machine-image"
src="/images/knitting-machine.webp"
alt=""
width="1113"
height="1316"
/>
</div>
<div className="loader__center">
<p className="loader__eyebrow">Preparing the loom</p>
<p className="loader__title">
From yarn
<br />
<em>to structure.</em>
</p>
<div className="loader__brand">
<img
className="loader__logo"
src="/images/RRSLOGO.png"
alt="Radhe Radhe Synthetics"
width="1024"
height="809"
/>
<p className="loader__message">From yarn to repeat production.</p>
</div>
</div>
<div className="loader__handoff" aria-hidden="true" />
<span className="loader__announcement">
Loading Radhe Radhe Synthetics
</span>
+3 -3
View File
@@ -3,8 +3,8 @@
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 32px;
border-block: 1px solid var(--line);
padding: 42px 0;
margin-top: 78px;
padding: 38px 0 42px;
margin-top: 42px;
}
.stats__item {
min-width: 0;
@@ -14,7 +14,7 @@
font-size: 13px;
font-weight: 500;
line-height: 1.6;
color: var(--muted);
color: var(--industrial);
}
.stats__value {
font-family: var(--serif);
+15 -10
View File
@@ -12,25 +12,30 @@ export const company = Object.freeze({
export const navigation = [
{ to: "/", label: "Home" },
{ to: "/fabrics", label: "Fabrics" },
{ to: "/about", label: "About" },
{ to: "/about", label: "Manufacturing" },
{ to: "/contact", label: "Contact" },
];
export const capabilities = [
{
title: "Develop",
subtitle: "Continuous fabric development",
text: "Different structures call for different yarns, blends and machine configurations. RRS continually develops new knitted constructions for evolving apparel requirements.",
title: "01 · Develop",
subtitle: "Define the construction",
text: "The requirement begins with the intended application, yarn, blend, structure and fabric character.",
},
{
title: "Repeat",
subtitle: "Consistency in bulk production",
text: "A successful development must remain dependable when production scales. RRS focuses on maintaining repeatability and quality across bulk manufacturing.",
title: "02 · Configure",
subtitle: "Match yarn to machine",
text: "Machine configuration and yarn selection are aligned to the construction being developed.",
},
{
title: "Manufacture",
subtitle: "Extensive circular-knitting capability",
text: "A broad range of circular-knitting configurations allows RRS to work across different structures, materials and fabric characteristics.",
title: "03 · Manufacture",
subtitle: "Circular knitting at scale",
text: "The approved construction moves into greige production across the appropriate circular-knitting setup.",
},
{
title: "04 · Repeat",
subtitle: "Maintain bulk consistency",
text: "Successful developments are reproduced with repeatability across commercial manufacturing quantities.",
},
];
+5 -5
View File
@@ -81,12 +81,12 @@ export default function About() {
return (
<>
<PageHero
label="About RRS"
label="Manufacturing at RRS"
title={
<>
Built around
<br />
<em>the fabric.</em>
<em>repeatable production.</em>
</>
}
>
@@ -100,12 +100,12 @@ export default function About() {
<section className="philosophy">
<SectionHeading
centered
label="Our philosophy"
label="Our manufacturing discipline"
title={
<>
Consistency
Develop with curiosity.
<br />
<em>and curiosity.</em>
<em>Produce with consistency.</em>
</>
}
>
+5 -5
View File
@@ -52,19 +52,19 @@ export default function Contact() {
return (
<>
<PageHero
label="Contact RRS"
label="Request a quote"
title={
<>
Let’s talk
Bring us your
<br />
<em>fabric.</em>
<em>fabric requirement.</em>
</>
}
texture="structured"
>
<p>
Whether you’re discussing an existing requirement, bulk production or
a new fabric construction, connect directly with RRS.
Share an existing requirement, bulk quantity or new construction with
RRS and begin a direct manufacturing conversation.
</p>
</PageHero>
<section className="whatsapp" id="whatsapp" tabIndex={-1}>
+19 -12
View File
@@ -4,9 +4,8 @@
flex-direction: column;
justify-content: center;
overflow: hidden;
min-height: 590px;
margin-top: 24px;
border-radius: 7px;
min-height: 768px;
margin-inline: calc(0px - var(--page-gutter));
color: var(--paper);
background: var(--ink);
}
@@ -21,11 +20,14 @@
.home-hero__shade {
position: absolute;
inset: 0;
background: #1419108f;
background:
linear-gradient(90deg, #132630e8 0%, #1f3239a8 54%, #17262f73 100%),
linear-gradient(0deg, #111b22b5 0%, transparent 45%);
}
.home-hero__content {
position: relative;
z-index: 1;
max-width: 900px;
padding: 65px 62px 90px;
}
.home-hero__title {
@@ -51,8 +53,8 @@
.home-hero__bottom {
position: absolute;
bottom: 0;
left: 32px;
right: 32px;
left: var(--page-gutter);
right: var(--page-gutter);
display: flex;
justify-content: space-between;
gap: 20px;
@@ -128,6 +130,9 @@
padding: 58px 0;
border-bottom: 1px solid var(--line);
}
.process__item:nth-child(even) {
background: linear-gradient(90deg, transparent, #49667808, transparent);
}
.process__item:nth-child(even) .process__visual {
order: -1;
}
@@ -137,9 +142,12 @@
}
.process__verb {
margin: 0 0 24px;
font-size: 14px;
font-family: var(--mono);
font-size: 11px;
font-weight: 500;
color: var(--muted);
color: var(--industrial);
letter-spacing: 0.05em;
text-transform: uppercase;
}
.process__title {
margin: 0 0 22px;
@@ -175,19 +183,18 @@
}
@media (max-width: 760px) {
.home-hero {
margin-top: 18px;
min-height: 560px;
}
.home-hero__content {
padding: 42px 26px 130px;
padding: 42px var(--page-gutter) 130px;
}
.home-hero__title {
font-size: clamp(44px, 8.9vw, 68px);
margin-top: 32px;
}
.home-hero__bottom {
left: 26px;
right: 26px;
left: var(--page-gutter);
right: var(--page-gutter);
flex-direction: column;
gap: 8px;
padding: 15px 0;
+23 -31
View File
@@ -1,35 +1,22 @@
import { Link } from "react-router-dom";
import { capabilities, company } from "../data";
import { capabilities } from "../data";
import {
Action,
Arrow,
Eyebrow,
SectionHeading,
Textile,
WhatsAppAction,
} from "../components/Primitives";
import { ContactBanner } from "../components/Layout";
import Gallery from "../components/Gallery";
import Stats from "../components/Stats";
import "./Home.css";
const processItems = [
{
...capabilities[0],
image: "fine",
href: "/fabrics#developments",
},
{
...capabilities[2],
image: "structured",
href: "/fabrics#circular-knitting",
},
{
...capabilities[1],
image: "natural",
href: "/fabrics#production",
},
];
const processItems = capabilities.map((capability, index) => ({
...capability,
image: ["fine", "natural", "structured", "fine"][index],
href: index < 2 ? "/fabrics#applications" : "/fabrics#production",
}));
export default function Home() {
return (
@@ -45,29 +32,35 @@ export default function Home() {
/>
<div className="home-hero__shade" />
<div className="home-hero__content">
<Eyebrow>Circular knitted fabrics · RRS</Eyebrow>
<Eyebrow>Specialist circular-knitting manufacturer · RRS</Eyebrow>
<h1 className="home-hero__title">
Built to develop.
<br />
<em>Built to repeat.</em>
</h1>
<p className="home-hero__description">{company.description}</p>
<p className="home-hero__description">
Greige knitted fabrics developed around yarn, structure and
application—then manufactured for consistent commercial supply.
</p>
<div className="home-hero__actions">
<Action to="/fabrics" variant="light">
Explore our fabrics
</Action>
<WhatsAppAction variant="ghost">Talk to RRS</WhatsAppAction>
<Action to="/contact#whatsapp" variant="ghost">
Request a quote
</Action>
</div>
</div>
<div className="home-hero__bottom">
<span className="home-hero__tagline">
Consistency at scale. Continuous development.
Development · Circular knitting · Bulk production
</span>
<span className="home-hero__image-note">
Illustrative texture · Photography to follow
Factory photography scheduled for content handover
</span>
</div>
</section>
<Stats />
<Gallery preview />
<section className="home-intro">
<div className="home-intro__heading">
@@ -98,21 +91,20 @@ export default function Home() {
</Link>
</div>
</section>
<Stats />
<section className="process">
<SectionHeading
label="How we work"
label="Manufacturing process"
title={
<>
Behind the fabric:
From requirement
<br />
<em>our process.</em>
<em>to repeat production.</em>
</>
}
>
<p>
Development, circular knitting and repeatable bulk production work
as one discipline.
A direct sequence connects fabric development with dependable
commercial manufacturing.
</p>
</SectionHeading>
<div className="process__list">
@@ -123,7 +115,7 @@ export default function Home() {
<h3 className="process__title">{subtitle}</h3>
<p className="process__text">{text}</p>
<Link className="process__link" to={href}>
Explore this capability <Arrow diagonal />
See our capability <Arrow diagonal />
</Link>
</div>
<Textile className="process__visual" kind={image} />
-46
View File
@@ -1,46 +0,0 @@
struct Params {
time: f32,
progress: f32,
aspect: f32,
padding: f32,
}
@group(0) @binding(0) var<uniform> params: Params;
fn thread(value: f32, width: f32) -> f32 {
return pow(0.5 + 0.5 * cos(value), width);
}
@fragment
fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
let p = vec2f(uv.x * params.aspect, uv.y);
let drift = sin(p.y * 18.0 + params.time * 0.42) * 0.018;
let warp = thread((p.x + drift) * 310.0, 7.0);
let weft = thread((p.y + sin(p.x * 13.0) * 0.006) * 280.0, 8.0);
let crossing = step(0.5, fract(floor(p.x * 49.0) * 0.5 + floor(p.y * 46.0) * 0.5));
let overUnder = mix(warp * 0.58 + weft, warp + weft * 0.55, crossing);
let irregularity = sin(p.x * 127.0 + sin(p.y * 31.0)) * 0.025;
let revealEdge = params.progress + sin(uv.y * 9.0 + params.time * 0.55) * 0.035;
let woven = 1.0 - smoothstep(revealEdge - 0.15, revealEdge + 0.04, uv.x);
let looseYarn = thread((p.x + sin(p.y * 8.0 + params.time) * 0.035) * 74.0, 10.0);
let wovenMask = smoothstep(0.16, 0.72, overUnder + irregularity);
let looseMask = smoothstep(0.24, 0.78, looseYarn);
let threadMask = mix(looseMask * 0.72, wovenMask, woven);
let slider = smoothstep(0.0, 1.0, params.progress);
let dyed = 1.0 - smoothstep(slider - 0.025, slider + 0.025, uv.x);
let greige = vec3f(0.69, 0.62, 0.51);
let madder = vec3f(0.72, 0.24, 0.12);
let indigo = vec3f(0.08, 0.34, 0.58);
let dyeColor = mix(madder, indigo, smoothstep(0.15, 0.9, uv.x));
let threadColor = mix(greige, dyeColor, dyed);
let shadow = vec3f(0.105, 0.10, 0.082);
let highlight = mix(vec3f(0.90, 0.84, 0.72), dyeColor * 1.35, dyed);
var color = mix(shadow, threadColor, threadMask);
color += highlight * pow(max(warp, weft), 10.0) * 0.14 * woven;
let vignette = smoothstep(0.82, 0.28, distance(uv, vec2f(0.5)));
color *= 0.7 + vignette * 0.3;
return vec4f(color, 1.0);
}
+13 -7
View File
@@ -5,7 +5,7 @@ const pages = [
["/", "Built to develop."],
["/fabrics", "Different yarns."],
["/about", "Built around"],
["/contact", "Let’s talk"],
["/contact", "Bring us your"],
];
for (const width of [1440, 768, 390, 320]) {
@@ -24,6 +24,7 @@ for (const width of [1440, 768, 390, 320]) {
heading,
);
await page.evaluate(() => document.fonts.ready);
await expect(page.locator(".loader")).toHaveCount(0, { timeout: 3500 });
for (const image of await page.locator("img").all()) {
await image.scrollIntoViewIfNeeded();
await expect(image).toHaveJSProperty("complete", true);
@@ -41,8 +42,8 @@ for (const width of [1440, 768, 390, 320]) {
(image) => !image.complete || !image.naturalWidth,
).length,
fontsLoaded:
document.fonts.check('16px "Instrument Serif"') &&
document.fonts.check('16px "DM Sans"'),
document.fonts.check('16px "Roboto Condensed"') &&
document.fonts.check('16px "Noto Sans"'),
contentWidthRatio:
document.querySelector("#main-content").getBoundingClientRect()
.width / window.innerWidth,
@@ -109,7 +110,7 @@ test("mobile navigation closes on selection and Escape", async ({ page }) => {
await toggle.click();
await page
.getByRole("navigation", { name: "Main navigation" })
.getByRole("link", { name: "About", exact: true })
.getByRole("link", { name: "Manufacturing", exact: true })
.click();
await expect(page).toHaveURL("/about");
await expect(toggle).toHaveAttribute("aria-expanded", "false");
@@ -191,7 +192,7 @@ test("every page section unveils once when scrolled into view", async ({
}
});
test("homepage feature headings are centered semantic h2 elements", async ({
test("homepage presents proof, fabrics and process in that order", async ({
page,
}) => {
await page.goto("/");
@@ -201,12 +202,17 @@ test("homepage feature headings are centered semantic h2 elements", async ({
});
const developmentsHeading = page.getByRole("heading", {
level: 2,
name: "Structure changes everything.",
name: "What we make. What we can develop.",
});
await expect(fabricsHeading).toHaveCSS("text-align", "center");
await expect(developmentsHeading.locator("..").locator("..")).toHaveClass(
/section-heading--centered/,
);
const sections = await page
.locator("#main-content > section")
.evaluateAll((nodes) => nodes.map((node) => node.classList[0]));
expect(sections.indexOf("stats")).toBeLessThan(sections.indexOf("gallery"));
expect(sections.indexOf("gallery")).toBeLessThan(sections.indexOf("process"));
});
test("capacity values roll in opposite directions and settle at 60–70", async ({
@@ -261,7 +267,7 @@ test("the woven loading page introduces the site and clears", async ({
await page.goto("/");
const loader = page.locator(".loader");
await expect(loader).toContainText("Loading Radhe Radhe Synthetics");
await expect(page.locator(".loader__canvas")).toHaveCount(1);
await expect(page.locator(".loader__machine-image")).toHaveCount(1);
await expect(loader).toHaveCount(0, { timeout: 3500 });
});